ಯೂನಿಫಾರ್ಮ್ ಬಫರ್ ಆಬ್ಜೆಕ್ಟ್ಸ್ (UBOs) ಮೂಲಕ ಸುಧಾರಿತ WebGL ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಿ. ಶೇಡರ್ ಡೇಟಾವನ್ನು ದಕ್ಷವಾಗಿ ವರ್ಗಾಯಿಸಲು, ರೆಂಡರಿಂಗ್ ಅನ್ನು ಆಪ್ಟಿಮೈಜ್ ಮಾಡಲು ಮತ್ತು ಜಾಗತಿಕ 3D ಅಪ್ಲಿಕೇಶನ್ಗಳಿಗಾಗಿ WebGL2 ಅನ್ನು ಕರಗತ ಮಾಡಿಕೊಳ್ಳಲು ಕಲಿಯಿರಿ. ಈ ಮಾರ್ಗದರ್ಶಿ ಅನುಷ್ಠಾನ, std140 ಲೇಔಟ್ ಮತ್ತು ಉತ್ತಮ ಅಭ್ಯಾಸಗಳನ್ನು ಒಳಗೊಂಡಿದೆ.
WebGL ಯೂನಿಫಾರ್ಮ್ ಬಫರ್ ಆಬ್ಜೆಕ್ಟ್ಸ್: ದಕ್ಷ ಶೇಡರ್ ಡೇಟಾ ವರ್ಗಾವಣೆ
ವೆಬ್-ಆಧಾರಿತ 3D ಗ್ರಾಫಿಕ್ಸ್ನ ಕ್ರಿಯಾತ್ಮಕ ಜಗತ್ತಿನಲ್ಲಿ, ಕಾರ್ಯಕ್ಷಮತೆ ಅತ್ಯಂತ ಮುಖ್ಯವಾಗಿದೆ. WebGL ಅಪ್ಲಿಕೇಶನ್ಗಳು ಹೆಚ್ಚು ಅತ್ಯಾಧುನಿಕವಾಗುತ್ತಿದ್ದಂತೆ, ಶೇಡರ್ಗಳಿಗಾಗಿ ದೊಡ್ಡ ಪ್ರಮಾಣದ ಡೇಟಾವನ್ನು ದಕ್ಷವಾಗಿ ನಿರ್ವಹಿಸುವುದು ನಿರಂತರ ಸವಾಲಾಗಿದೆ. WebGL2 (ಇದು OpenGL ES 3.0 ನೊಂದಿಗೆ ಹೊಂದಿಕೊಳ್ಳುತ್ತದೆ) ಅನ್ನು ಗುರಿಯಾಗಿಸಿಕೊಂಡಿರುವ ಡೆವಲಪರ್ಗಳಿಗೆ, ಯೂನಿಫಾರ್ಮ್ ಬಫರ್ ಆಬ್ಜೆಕ್ಟ್ಸ್ (UBOs) ಈ ಸಮಸ್ಯೆಗೆ ಪ್ರಬಲ ಪರಿಹಾರವನ್ನು ನೀಡುತ್ತವೆ. ಈ ಸಮಗ್ರ ಮಾರ್ಗದರ್ಶಿ ನಿಮ್ಮನ್ನು UBOಗಳ ಆಳಕ್ಕೆ ಕೊಂಡೊಯ್ಯುತ್ತದೆ, ಅವುಗಳ ಅಗತ್ಯತೆ, ಅವು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತವೆ ಮತ್ತು ಜಾಗತಿಕ ಪ್ರೇಕ್ಷಕರಿಗಾಗಿ ಉನ್ನತ-ಕಾರ್ಯಕ್ಷಮತೆಯ, ದೃಷ್ಟಿಗೆ ಬೆರಗುಗೊಳಿಸುವ WebGL ಅನುಭವಗಳನ್ನು ರಚಿಸಲು ಅವುಗಳ ಸಂಪೂರ್ಣ ಸಾಮರ್ಥ್ಯವನ್ನು ಹೇಗೆ ಬಳಸಿಕೊಳ್ಳುವುದು ಎಂಬುದನ್ನು ವಿವರಿಸುತ್ತದೆ.
ನೀವು ಸಂಕೀರ್ಣ ಡೇಟಾ ದೃಶ್ಯೀಕರಣ, ತಲ್ಲೀನಗೊಳಿಸುವ ಆಟ, ಅಥವಾ ಅತ್ಯಾಧುನಿಕ ವರ್ಧಿತ ರಿಯಾಲಿಟಿ ಅನುಭವವನ್ನು ನಿರ್ಮಿಸುತ್ತಿರಲಿ, ನಿಮ್ಮ ರೆಂಡರಿಂಗ್ ಪೈಪ್ಲೈನ್ ಅನ್ನು ಆಪ್ಟಿಮೈಜ್ ಮಾಡಲು ಮತ್ತು ನಿಮ್ಮ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಪ್ರಪಂಚದಾದ್ಯಂತದ ವಿವಿಧ ಸಾಧನಗಳು ಮತ್ತು ಪ್ಲಾಟ್ಫಾರ್ಮ್ಗಳಲ್ಲಿ ಸರಾಗವಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುವುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಲು UBOಗಳನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವುದು ನಿರ್ಣಾಯಕವಾಗಿದೆ.
ಪರಿಚಯ: ಶೇಡರ್ ಡೇಟಾ ನಿರ್ವಹಣೆಯ ವಿಕಸನ
ನಾವು UBOಗಳ ನಿರ್ದಿಷ್ಟತೆಗಳನ್ನು ಪರಿಶೀಲಿಸುವ ಮೊದಲು, ಶೇಡರ್ ಡೇಟಾ ನಿರ್ವಹಣೆಯ ಭೂದೃಶ್ಯವನ್ನು ಮತ್ತು UBOಗಳು ಏಕೆ ಅಂತಹ ಮಹತ್ವದ ಪ್ರಗತಿಯನ್ನು ಪ್ರತಿನಿಧಿಸುತ್ತವೆ ಎಂಬುದನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವುದು ಅತ್ಯಗತ್ಯ. WebGL ನಲ್ಲಿ, ಶೇಡರ್ಗಳು ಗ್ರಾಫಿಕ್ಸ್ ಪ್ರೊಸೆಸಿಂಗ್ ಯೂನಿಟ್ (GPU) ನಲ್ಲಿ ಚಲಿಸುವ ಸಣ್ಣ ಪ್ರೋಗ್ರಾಂಗಳಾಗಿವೆ, ನಿಮ್ಮ 3D ಮಾದರಿಗಳನ್ನು ಹೇಗೆ ರೆಂಡರ್ ಮಾಡಬೇಕೆಂದು ನಿರ್ದೇಶಿಸುತ್ತವೆ. ತಮ್ಮ ಕಾರ್ಯಗಳನ್ನು ನಿರ್ವಹಿಸಲು, ಈ ಶೇಡರ್ಗಳಿಗೆ ಸಾಮಾನ್ಯವಾಗಿ "ಯೂನಿಫಾರ್ಮ್ಗಳು" ಎಂದು ಕರೆಯಲ್ಪಡುವ ಬಾಹ್ಯ ಡೇಟಾ ಅಗತ್ಯವಿರುತ್ತದೆ.
WebGL1/OpenGL ES 2.0 ನಲ್ಲಿ ಯೂನಿಫಾರ್ಮ್ಗಳ ಸವಾಲು
ಮೂಲ WebGL ನಲ್ಲಿ (OpenGL ES 2.0 ಆಧಾರಿತ), ಯೂನಿಫಾರ್ಮ್ಗಳನ್ನು ಪ್ರತ್ಯೇಕವಾಗಿ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿತ್ತು. ಶೇಡರ್ ಪ್ರೋಗ್ರಾಂನಲ್ಲಿರುವ ಪ್ರತಿಯೊಂದು ಯೂನಿಫಾರ್ಮ್ ವೇರಿಯಬಲ್ ಅನ್ನು ಅದರ ಸ್ಥಳದಿಂದ (gl.getUniformLocation ಬಳಸಿ) ಗುರುತಿಸಬೇಕಾಗಿತ್ತು ಮತ್ತು ನಂತರ gl.uniform1f, gl.uniformMatrix4fv, ಮತ್ತು ಮುಂತಾದ ನಿರ್ದಿಷ್ಟ ಫಂಕ್ಷನ್ಗಳನ್ನು ಬಳಸಿ ಅಪ್ಡೇಟ್ ಮಾಡಬೇಕಾಗಿತ್ತು. ಈ ವಿಧಾನವು, ಸರಳ ದೃಶ್ಯಗಳಿಗೆ ನೇರವಾಗಿದ್ದರೂ, ಅಪ್ಲಿಕೇಶನ್ಗಳು ಸಂಕೀರ್ಣತೆಯಲ್ಲಿ ಬೆಳೆದಂತೆ ಹಲವಾರು ಸವಾಲುಗಳನ್ನು ಒಡ್ಡಿತು:
- ಹೆಚ್ಚಿನ ಸಿಪಿಯು ಓವರ್ಹೆಡ್: ಪ್ರತಿಯೊಂದು
gl.uniform...ಕರೆ ಸೆಂಟ್ರಲ್ ಪ್ರೊಸೆಸಿಂಗ್ ಯೂನಿಟ್ (ಸಿಪಿಯು) ಮತ್ತು ಜಿಪಿಯು ನಡುವೆ ಸಂದರ್ಭ ಬದಲಾವಣೆಯನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ, ಇದು ಗಣನಾತ್ಮಕವಾಗಿ ದುಬಾರಿಯಾಗಬಹುದು. ಅನೇಕ ವಸ್ತುಗಳಿರುವ ದೃಶ್ಯಗಳಲ್ಲಿ, ಪ್ರತಿಯೊಂದಕ್ಕೂ ವಿಶಿಷ್ಟವಾದ ಯೂನಿಫಾರ್ಮ್ ಡೇಟಾ (ಉದಾಹರಣೆಗೆ, ವಿಭಿನ್ನ ರೂಪಾಂತರ ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳು, ಬಣ್ಣಗಳು, ಅಥವಾ ವಸ್ತು ಗುಣಲಕ್ಷಣಗಳು) ಅಗತ್ಯವಿದ್ದಾಗ, ಈ ಕರೆಗಳು ವೇಗವಾಗಿ ಸಂಗ್ರಹಗೊಂಡು ಗಮನಾರ್ಹ ಅಡಚಣೆಯಾಗುತ್ತವೆ. ಈ ಓವರ್ಹೆಡ್ ವಿಶೇಷವಾಗಿ ಕಡಿಮೆ-ಮಟ್ಟದ ಸಾಧನಗಳಲ್ಲಿ ಅಥವಾ ಅನೇಕ ವಿಭಿನ್ನ ರೆಂಡರ್ ಸ್ಥಿತಿಗಳಿರುವ ಸನ್ನಿವೇಶಗಳಲ್ಲಿ ಗಮನಾರ್ಹವಾಗಿರುತ್ತದೆ. - ಪುನರಾವರ್ತಿತ ಡೇಟಾ ವರ್ಗಾವಣೆ: ಒಂದೇ ರೀತಿಯ ಯೂನಿಫಾರ್ಮ್ ಡೇಟಾವನ್ನು (ಉದಾ., ಕ್ಯಾಮರಾ ಸ್ಥಾನಕ್ಕೆ ಸ್ಥಿರವಾಗಿರುವ ಪ್ರೊಜೆಕ್ಷನ್ ಮತ್ತು ವ್ಯೂ ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳು) ಅನೇಕ ಶೇಡರ್ ಪ್ರೋಗ್ರಾಂಗಳು ಹಂಚಿಕೊಂಡರೆ, ಆ ಡೇಟಾವನ್ನು ಪ್ರತಿ ಪ್ರೋಗ್ರಾಂಗೆ ಪ್ರತ್ಯೇಕವಾಗಿ ಜಿಪಿಯುಗೆ ಕಳುಹಿಸಬೇಕಾಗಿತ್ತು. ಇದು ಅಸಮರ್ಥ ಮೆಮೊರಿ ಬಳಕೆ ಮತ್ತು ಅನಗತ್ಯ ಡೇಟಾ ವರ್ಗಾವಣೆಗೆ ಕಾರಣವಾಯಿತು, ಅಮೂಲ್ಯವಾದ ಬ್ಯಾಂಡ್ವಿಡ್ತ್ ಅನ್ನು ವ್ಯರ್ಥ ಮಾಡಿತು.
- ಸೀಮಿತ ಯೂನಿಫಾರ್ಮ್ ಸಂಗ್ರಹಣೆ: WebGL1 ಶೇಡರ್ ಘೋಷಿಸಬಹುದಾದ ವೈಯಕ್ತಿಕ ಯೂನಿಫಾರ್ಮ್ಗಳ ಸಂಖ್ಯೆಯ ಮೇಲೆ ತುಲನಾತ್ಮಕವಾಗಿ ಕಟ್ಟುನಿಟ್ಟಾದ ಮಿತಿಗಳನ್ನು ಹೊಂದಿದೆ. ಈ ಮಿತಿಯು ಸಂಕೀರ್ಣ ಶೇಡಿಂಗ್ ಮಾದರಿಗಳಿಗೆ ತ್ವರಿತವಾಗಿ ನಿರ್ಬಂಧಿತವಾಗಬಹುದು, ಉದಾಹರಣೆಗೆ ಭೌತಿಕವಾಗಿ ಆಧಾರಿತ ರೆಂಡರಿಂಗ್ (PBR) ವಸ್ತುಗಳು ಅನೇಕ ಟೆಕ್ಸ್ಚರ್ ಮ್ಯಾಪ್ಗಳು ಮತ್ತು ವಸ್ತು ಗುಣಲಕ್ಷಣಗಳೊಂದಿಗೆ.
- ಕಳಪೆ ಬ್ಯಾಚಿಂಗ್ ಸಾಮರ್ಥ್ಯಗಳು: ಪ್ರತಿ-ವಸ್ತುವಿನ ಆಧಾರದ ಮೇಲೆ ಯೂನಿಫಾರ್ಮ್ಗಳನ್ನು ನವೀಕರಿಸುವುದು ಡ್ರಾಯಿಂಗ್ ಕರೆಗಳನ್ನು ಪರಿಣಾಮಕಾರಿಯಾಗಿ ಬ್ಯಾಚ್ ಮಾಡುವುದನ್ನು ಕಷ್ಟಕರವಾಗಿಸುತ್ತದೆ. ಬ್ಯಾಚಿಂಗ್ ಒಂದು ನಿರ್ಣಾಯಕ ಆಪ್ಟಿಮೈಸೇಶನ್ ತಂತ್ರವಾಗಿದ್ದು, ಇದರಲ್ಲಿ ಅನೇಕ ವಸ್ತುಗಳನ್ನು ಒಂದೇ ಡ್ರಾ ಕರೆಯೊಂದಿಗೆ ರೆಂಡರ್ ಮಾಡಲಾಗುತ್ತದೆ, ಎಪಿಐ ಓವರ್ಹೆಡ್ ಅನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ. ಯೂನಿಫಾರ್ಮ್ ಡೇಟಾವು ಪ್ರತಿ ವಸ್ತುವಿಗೆ ಬದಲಾಗಬೇಕಾದಾಗ, ಬ್ಯಾಚಿಂಗ್ ಸಾಮಾನ್ಯವಾಗಿ ಮುರಿಯಲ್ಪಡುತ್ತದೆ, ಇದು ರೆಂಡರಿಂಗ್ ಕಾರ್ಯಕ್ಷಮತೆಯ ಮೇಲೆ ಪರಿಣಾಮ ಬೀರುತ್ತದೆ, ವಿಶೇಷವಾಗಿ ವಿವಿಧ ಸಾಧನಗಳಲ್ಲಿ ಹೆಚ್ಚಿನ ಫ್ರೇಮ್ ದರಗಳನ್ನು ಗುರಿಯಾಗಿಸಿಕೊಂಡಾಗ.
ಈ ಮಿತಿಗಳು WebGL1 ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು, ವಿಶೇಷವಾಗಿ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ತ್ಯಾಗ ಮಾಡದೆ ಹೆಚ್ಚಿನ ದೃಶ್ಯ ನಿಷ್ಠೆ ಮತ್ತು ಸಂಕೀರ್ಣ ದೃಶ್ಯ ನಿರ್ವಹಣೆಯನ್ನು ಗುರಿಯಾಗಿಸಿಕೊಂಡಿರುವ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಅಳೆಯುವುದನ್ನು ಸವಾಲಾಗಿಸಿದವು. ಡೆವಲಪರ್ಗಳು ಆಗಾಗ್ಗೆ ಡೇಟಾವನ್ನು ಟೆಕ್ಸ್ಚರ್ಗಳಲ್ಲಿ ಪ್ಯಾಕ್ ಮಾಡುವುದು ಅಥವಾ ಗುಣಲಕ್ಷಣ ಡೇಟಾವನ್ನು ಹಸ್ತಚಾಲಿತವಾಗಿ ಇಂಟರ್ಲೀವ್ ಮಾಡುವಂತಹ ವಿವಿಧ ಪರಿಹಾರಗಳನ್ನು ಆಶ್ರಯಿಸುತ್ತಿದ್ದರು, ಆದರೆ ಈ ಪರಿಹಾರಗಳು ಸಂಕೀರ್ಣತೆಯನ್ನು ಹೆಚ್ಚಿಸಿದವು ಮತ್ತು ಯಾವಾಗಲೂ ಸೂಕ್ತ ಅಥವಾ ಸಾರ್ವತ್ರಿಕವಾಗಿ ಅನ್ವಯವಾಗುತ್ತಿರಲಿಲ್ಲ.
WebGL2 ಮತ್ತು UBOಗಳ ಶಕ್ತಿಯ ಪರಿಚಯ
WebGL2 ನ ಆಗಮನದೊಂದಿಗೆ, ಇದು OpenGL ES 3.0 ನ ಸಾಮರ್ಥ್ಯಗಳನ್ನು ವೆಬ್ಗೆ ತರುತ್ತದೆ, ಯೂನಿಫಾರ್ಮ್ ನಿರ್ವಹಣೆಗಾಗಿ ಹೊಸ ಮಾದರಿ ಹೊರಹೊಮ್ಮಿತು: ಯೂನಿಫಾರ್ಮ್ ಬಫರ್ ಆಬ್ಜೆಕ್ಟ್ಸ್ (UBOs). UBOಗಳು ಡೆವಲಪರ್ಗಳಿಗೆ ಬಹು ಯೂನಿಫಾರ್ಮ್ ವೇರಿಯಬಲ್ಗಳನ್ನು ಒಂದೇ ಬಫರ್ ಆಬ್ಜೆಕ್ಟ್ ಆಗಿ ಗುಂಪು ಮಾಡಲು ಅನುಮತಿಸುವ ಮೂಲಕ ಯೂನಿಫಾರ್ಮ್ ಡೇಟಾವನ್ನು ಹೇಗೆ ನಿರ್ವಹಿಸಲಾಗುತ್ತದೆ ಎಂಬುದನ್ನು ಮೂಲಭೂತವಾಗಿ ಬದಲಾಯಿಸುತ್ತವೆ. ಈ ಬಫರ್ ಅನ್ನು ನಂತರ ಜಿಪಿಯುನಲ್ಲಿ ಸಂಗ್ರಹಿಸಲಾಗುತ್ತದೆ ಮತ್ತು ಒಂದು ಅಥವಾ ಹೆಚ್ಚಿನ ಶೇಡರ್ ಪ್ರೋಗ್ರಾಂಗಳಿಂದ ದಕ್ಷವಾಗಿ ನವೀಕರಿಸಬಹುದು ಮತ್ತು ಪ್ರವೇಶಿಸಬಹುದು.
UBOಗಳ ಪರಿಚಯವು ಮೇಲೆ ತಿಳಿಸಿದ ಸವಾಲುಗಳನ್ನು ನೇರವಾಗಿ ಪರಿಹರಿಸುತ್ತದೆ, ಶೇಡರ್ಗಳಿಗೆ ದೊಡ್ಡ, ರಚನಾತ್ಮಕ ಡೇಟಾ ಸೆಟ್ಗಳನ್ನು ವರ್ಗಾಯಿಸಲು ದೃಢವಾದ ಮತ್ತು ದಕ್ಷವಾದ ಕಾರ್ಯವಿಧಾನವನ್ನು ಒದಗಿಸುತ್ತದೆ. ಅವು ಆಧುನಿಕ, ಉನ್ನತ-ಕಾರ್ಯಕ್ಷಮತೆಯ WebGL2 ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ನಿರ್ಮಿಸಲು ಮೂಲಾಧಾರವಾಗಿವೆ, ಸ್ವಚ್ಛ ಕೋಡ್, ಉತ್ತಮ ಸಂಪನ್ಮೂಲ ನಿರ್ವಹಣೆ ಮತ್ತು ಅಂತಿಮವಾಗಿ, ಸುಗಮ ಬಳಕೆದಾರರ ಅನುಭವಗಳಿಗೆ ದಾರಿ ಮಾಡಿಕೊಡುತ್ತವೆ. ಬ್ರೌಸರ್ನಲ್ಲಿ 3D ಗ್ರಾಫಿಕ್ಸ್ನ ಗಡಿಗಳನ್ನು ತಳ್ಳಲು ಬಯಸುವ ಯಾವುದೇ ಡೆವಲಪರ್ಗೆ, UBOಗಳು ಕರಗತ ಮಾಡಿಕೊಳ್ಳಬೇಕಾದ ಅತ್ಯಗತ್ಯ ಪರಿಕಲ್ಪನೆಯಾಗಿದೆ.
ಯೂನಿಫಾರ್ಮ್ ಬಫರ್ ಆಬ್ಜೆಕ್ಟ್ಸ್ (UBOs) ಎಂದರೇನು?
ಯೂನಿಫಾರ್ಮ್ ಬಫರ್ ಆಬ್ಜೆಕ್ಟ್ (UBO) WebGL2 ನಲ್ಲಿ ಯೂನಿಫಾರ್ಮ್ ವೇರಿಯಬಲ್ಗಳ ಸಂಗ್ರಹಗಳನ್ನು ಸಂಗ್ರಹಿಸಲು ವಿನ್ಯಾಸಗೊಳಿಸಲಾದ ವಿಶೇಷ ರೀತಿಯ ಬಫರ್ ಆಗಿದೆ. ಪ್ರತಿಯೊಂದು ಯೂನಿಫಾರ್ಮ್ ಅನ್ನು ಪ್ರತ್ಯೇಕವಾಗಿ ಕಳುಹಿಸುವ ಬದಲು, ನೀವು ಅವುಗಳನ್ನು ಒಂದೇ ಡೇಟಾ ಬ್ಲಾಕ್ ಆಗಿ ಪ್ಯಾಕ್ ಮಾಡಿ, ಈ ಬ್ಲಾಕ್ ಅನ್ನು ಜಿಪಿಯು ಬಫರ್ಗೆ ಅಪ್ಲೋಡ್ ಮಾಡಿ, ಮತ್ತು ನಂತರ ಆ ಬಫರ್ ಅನ್ನು ನಿಮ್ಮ ಶೇಡರ್ ಪ್ರೋಗ್ರಾಂ(ಗಳಿಗೆ) ಬಂಧಿಸುತ್ತೀರಿ. ಇದನ್ನು ಜಿಪಿಯುನಲ್ಲಿರುವ ಒಂದು ಮೀಸಲಾದ ಮೆಮೊರಿ ಪ್ರದೇಶವೆಂದು ಯೋಚಿಸಿ, ಅಲ್ಲಿ ನಿಮ್ಮ ಶೇಡರ್ಗಳು ಡೇಟಾವನ್ನು ದಕ್ಷವಾಗಿ ಹುಡುಕಬಹುದು, ಹಾಗೆಯೇ ಆಟ್ರಿಬ್ಯೂಟ್ ಬಫರ್ಗಳು ವರ್ಟೆಕ್ಸ್ ಡೇಟಾವನ್ನು ಸಂಗ್ರಹಿಸುತ್ತವೆ.
ಯೂನಿಫಾರ್ಮ್ಗಳನ್ನು ನವೀಕರಿಸಲು ಪ್ರತ್ಯೇಕ ಎಪಿಐ ಕರೆಗಳ ಸಂಖ್ಯೆಯನ್ನು ಕಡಿಮೆ ಮಾಡುವುದು ಇದರ ಮೂಲ ಕಲ್ಪನೆ. ಸಂಬಂಧಿತ ಯೂನಿಫಾರ್ಮ್ಗಳನ್ನು ಒಂದೇ ಬಫರ್ನಲ್ಲಿ ಸೇರಿಸುವ ಮೂಲಕ, ನೀವು ಅನೇಕ ಸಣ್ಣ ಡೇಟಾ ವರ್ಗಾವಣೆಗಳನ್ನು ಒಂದು ದೊಡ್ಡ, ಹೆಚ್ಚು ದಕ್ಷವಾದ ಕಾರ್ಯಾಚರಣೆಯಾಗಿ ಕ್ರೋಢೀಕರಿಸುತ್ತೀರಿ.
ಮೂಲ ಪರಿಕಲ್ಪನೆಗಳು ಮತ್ತು ಪ್ರಯೋಜನಗಳು
ನಿಮ್ಮ WebGL ಯೋಜನೆಗಳ ಮೇಲೆ ಅವುಗಳ ಪ್ರಭಾವವನ್ನು ಶ್ಲಾಘಿಸಲು UBOಗಳ ಪ್ರಮುಖ ಪ್ರಯೋಜನಗಳನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವುದು ನಿರ್ಣಾಯಕವಾಗಿದೆ:
-
ಕಡಿಮೆಯಾದ ಸಿಪಿಯು-ಜಿಪಿಯು ಓವರ್ಹೆಡ್: ಇದು ಬಹುಶಃ ಅತ್ಯಂತ ಮಹತ್ವದ ಪ್ರಯೋಜನವಾಗಿದೆ. ಪ್ರತಿ ಫ್ರೇಮ್ಗೆ ಡಜನ್ಗಟ್ಟಲೆ ಅಥವಾ ನೂರಾರು ವೈಯಕ್ತಿಕ
gl.uniform...ಕರೆಗಳ ಬದಲು, ನೀವು ಈಗ ಒಂದೇgl.bufferDataಅಥವಾgl.bufferSubDataಕರೆಯೊಂದಿಗೆ ದೊಡ್ಡ ಗುಂಪಿನ ಯೂನಿಫಾರ್ಮ್ಗಳನ್ನು ನವೀಕರಿಸಬಹುದು. ಇದು ಸಿಪಿಯು ಮತ್ತು ಜಿಪಿಯು ನಡುವಿನ ಸಂವಹನ ಓವರ್ಹೆಡ್ ಅನ್ನು ತೀವ್ರವಾಗಿ ಕಡಿಮೆ ಮಾಡುತ್ತದೆ, ಇತರ ಕಾರ್ಯಗಳಿಗಾಗಿ (ಗೇಮ್ ಲಾಜಿಕ್, ಭೌತಶಾಸ್ತ್ರ, ಅಥವಾ ಯುಐ ಅಪ್ಡೇಟ್ಗಳಂತಹ) ಸಿಪಿಯು ಸೈಕಲ್ಗಳನ್ನು ಮುಕ್ತಗೊಳಿಸುತ್ತದೆ ಮತ್ತು ಒಟ್ಟಾರೆ ರೆಂಡರಿಂಗ್ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಸುಧಾರಿಸುತ್ತದೆ. ಇದು ವಿಶೇಷವಾಗಿ ಸಿಪಿಯು-ಜಿಪಿಯು ಸಂವಹನವು ಅಡಚಣೆಯಾಗಿರುವ ಸಾಧನಗಳಲ್ಲಿ ಪ್ರಯೋಜನಕಾರಿಯಾಗಿದೆ, ಇದು ಮೊಬೈಲ್ ಪರಿಸರಗಳು ಅಥವಾ ಸಂಯೋಜಿತ ಗ್ರಾಫಿಕ್ಸ್ ಪರಿಹಾರಗಳಲ್ಲಿ ಸಾಮಾನ್ಯವಾಗಿದೆ. -
ಬ್ಯಾಚಿಂಗ್ ಮತ್ತು ಇನ್ಸ್ಟನ್ಸಿಂಗ್ ದಕ್ಷತೆ: UBOಗಳು ಇನ್ಸ್ಟನ್ಸ್ಡ್ ರೆಂಡರಿಂಗ್ನಂತಹ ಸುಧಾರಿತ ರೆಂಡರಿಂಗ್ ತಂತ್ರಗಳನ್ನು ಹೆಚ್ಚು ಸುಗಮಗೊಳಿಸುತ್ತವೆ. ನೀವು ಸೀಮಿತ ಸಂಖ್ಯೆಯ ಇನ್ಸ್ಟನ್ಸ್ಗಳಿಗಾಗಿ ಪ್ರತಿ-ಇನ್ಸ್ಟನ್ಸ್ ಡೇಟಾವನ್ನು (ಉದಾ., ಮಾಡೆಲ್ ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳು, ಬಣ್ಣಗಳು) ನೇರವಾಗಿ UBO ಒಳಗೆ ಸಂಗ್ರಹಿಸಬಹುದು. UBOಗಳನ್ನು
gl.drawArraysInstancedಅಥವಾgl.drawElementsInstancedನೊಂದಿಗೆ ಸಂಯೋಜಿಸುವ ಮೂಲಕ, ಒಂದೇ ಡ್ರಾ ಕರೆಯು ಸಾವಿರಾರು ಇನ್ಸ್ಟನ್ಸ್ಗಳನ್ನು ವಿಭಿನ್ನ ಗುಣಲಕ್ಷಣಗಳೊಂದಿಗೆ ರೆಂಡರ್ ಮಾಡಬಹುದು, ಎಲ್ಲವೂgl_InstanceIDಶೇಡರ್ ವೇರಿಯಬಲ್ ಬಳಸಿ UBO ಮೂಲಕ ತಮ್ಮ ವಿಶಿಷ್ಟ ಡೇಟಾವನ್ನು ದಕ್ಷವಾಗಿ ಪ್ರವೇಶಿಸುತ್ತವೆ. ಇದು ಗುಂಪುಗಳು, ಕಾಡುಗಳು, ಅಥವಾ ಕಣ ವ್ಯವಸ್ಥೆಗಳಂತಹ ಅನೇಕ ಒಂದೇ ರೀತಿಯ ಅಥವಾ ಹೋಲುವ ವಸ್ತುಗಳನ್ನು ಹೊಂದಿರುವ ದೃಶ್ಯಗಳಿಗೆ ಗೇಮ್-ಚೇಂಜರ್ ಆಗಿದೆ. - ಶೇಡರ್ಗಳಾದ್ಯಂತ ಸ್ಥಿರ ಡೇಟಾ: UBOಗಳು ನಿಮಗೆ ಶೇಡರ್ನಲ್ಲಿ ಯೂನಿಫಾರ್ಮ್ಗಳ ಬ್ಲಾಕ್ ಅನ್ನು ವ್ಯಾಖ್ಯಾನಿಸಲು ಮತ್ತು ನಂತರ ಒಂದೇ UBO ಬಫರ್ ಅನ್ನು ಅನೇಕ ವಿಭಿನ್ನ ಶೇಡರ್ ಪ್ರೋಗ್ರಾಂಗಳಲ್ಲಿ ಹಂಚಿಕೊಳ್ಳಲು ಅನುವು ಮಾಡಿಕೊಡುತ್ತದೆ. ಉದಾಹರಣೆಗೆ, ನಿಮ್ಮ ಪ್ರೊಜೆಕ್ಷನ್ ಮತ್ತು ವ್ಯೂ ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳು, ಕ್ಯಾಮರಾದ ದೃಷ್ಟಿಕೋನವನ್ನು ವ್ಯಾಖ್ಯಾನಿಸುತ್ತವೆ, ಒಂದು UBO ನಲ್ಲಿ ಸಂಗ್ರಹಿಸಬಹುದು ಮತ್ತು ನಿಮ್ಮ ಎಲ್ಲಾ ಶೇಡರ್ಗಳಿಗೆ (ಅಪಾರದರ್ಶಕ ವಸ್ತುಗಳು, ಪಾರದರ್ಶಕ ವಸ್ತುಗಳು, ಪೋಸ್ಟ್-ಪ್ರೊಸೆಸಿಂಗ್ ಪರಿಣಾಮಗಳು ಇತ್ಯಾದಿಗಳಿಗೆ) ಲಭ್ಯವಾಗುವಂತೆ ಮಾಡಬಹುದು. ಇದು ಡೇಟಾ ಸ್ಥಿರತೆಯನ್ನು ಖಚಿತಪಡಿಸುತ್ತದೆ (ಎಲ್ಲಾ ಶೇಡರ್ಗಳು ಒಂದೇ ಕ್ಯಾಮರಾ ನೋಟವನ್ನು ನೋಡುತ್ತವೆ), ಕ್ಯಾಮರಾ ನಿರ್ವಹಣೆಯನ್ನು ಕೇಂದ್ರೀಕರಿಸುವ ಮೂಲಕ ಕೋಡ್ ಅನ್ನು ಸರಳಗೊಳಿಸುತ್ತದೆ, ಮತ್ತು ಪುನರಾವರ್ತಿತ ಡೇಟಾ ವರ್ಗಾವಣೆಗಳನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ.
- ಮೆಮೊರಿ ದಕ್ಷತೆ: ಸಂಬಂಧಿತ ಯೂನಿಫಾರ್ಮ್ಗಳನ್ನು ಒಂದೇ ಬಫರ್ನಲ್ಲಿ ಪ್ಯಾಕ್ ಮಾಡುವ ಮೂಲಕ, UBOಗಳು ಕೆಲವೊಮ್ಮೆ ಜಿಪಿಯುನಲ್ಲಿ ಹೆಚ್ಚು ದಕ್ಷವಾದ ಮೆಮೊರಿ ಬಳಕೆಗೆ ಕಾರಣವಾಗಬಹುದು, ವಿಶೇಷವಾಗಿ ಅನೇಕ ಸಣ್ಣ ಯೂನಿಫಾರ್ಮ್ಗಳು ಪ್ರತಿ-ಯೂನಿಫಾರ್ಮ್ ಓವರ್ಹೆಡ್ ಅನ್ನು ಉಂಟುಮಾಡಿದಾಗ. ಇದಲ್ಲದೆ, ಪ್ರೋಗ್ರಾಂಗಳಾದ್ಯಂತ UBOಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳುವುದು ಎಂದರೆ ಡೇಟಾವು ಜಿಪಿಯು ಮೆಮೊರಿಯಲ್ಲಿ ಒಮ್ಮೆ ಮಾತ್ರ ಇರಬೇಕಾಗುತ್ತದೆ, ಅದನ್ನು ಬಳಸುವ ಪ್ರತಿಯೊಂದು ಪ್ರೋಗ್ರಾಂಗೆ ನಕಲು ಮಾಡುವ ಬದಲು. ಇದು ಮೆಮೊರಿ-ನಿರ್ಬಂಧಿತ ಪರಿಸರಗಳಲ್ಲಿ, ಉದಾಹರಣೆಗೆ ಮೊಬೈಲ್ ಬ್ರೌಸರ್ಗಳಲ್ಲಿ, ನಿರ್ಣಾಯಕವಾಗಬಹುದು.
-
ಹೆಚ್ಚಿದ ಯೂನಿಫಾರ್ಮ್ ಸಂಗ್ರಹಣೆ: UBOಗಳು WebGL1 ನ ವೈಯಕ್ತಿಕ ಯೂನಿಫಾರ್ಮ್ ಎಣಿಕೆ ಮಿತಿಗಳನ್ನು ಬೈಪಾಸ್ ಮಾಡುವ ಮಾರ್ಗವನ್ನು ಒದಗಿಸುತ್ತವೆ. ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ನ ಒಟ್ಟು ಗಾತ್ರವು ಸಾಮಾನ್ಯವಾಗಿ ವೈಯಕ್ತಿಕ ಯೂನಿಫಾರ್ಮ್ಗಳ ಗರಿಷ್ಠ ಸಂಖ್ಯೆಗಿಂತ ದೊಡ್ಡದಾಗಿದೆ, ಇದು ನಿಮ್ಮ ಶೇಡರ್ಗಳಲ್ಲಿ ಹೆಚ್ಚು ಸಂಕೀರ್ಣವಾದ ಡೇಟಾ ರಚನೆಗಳು ಮತ್ತು ವಸ್ತು ಗುಣಲಕ್ಷಣಗಳಿಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ, ಹಾರ್ಡ್ವೇರ್ ಮಿತಿಗಳನ್ನು ತಲುಪದೆಯೇ. WebGL2 ನ
gl.MAX_UNIFORM_BLOCK_SIZEಸಾಮಾನ್ಯವಾಗಿ ಕಿಲೋಬೈಟ್ಗಳಷ್ಟು ಡೇಟಾವನ್ನು ಅನುಮತಿಸುತ್ತದೆ, ಇದು ವೈಯಕ್ತಿಕ ಯೂನಿಫಾರ್ಮ್ ಮಿತಿಗಳನ್ನು ಮೀರುತ್ತದೆ.
UBOಗಳು vs. ಸ್ಟ್ಯಾಂಡರ್ಡ್ ಯೂನಿಫಾರ್ಮ್ಗಳು
ಮೂಲಭೂತ ವ್ಯತ್ಯಾಸಗಳನ್ನು ಮತ್ತು ಪ್ರತಿಯೊಂದು ವಿಧಾನವನ್ನು ಯಾವಾಗ ಬಳಸಬೇಕು ಎಂಬುದನ್ನು ಎತ್ತಿ ತೋರಿಸಲು ಇಲ್ಲಿ ಒಂದು ತ್ವರಿತ ಹೋಲಿಕೆಯಿದೆ:
| ವೈಶಿಷ್ಟ್ಯ | ಸ್ಟ್ಯಾಂಡರ್ಡ್ ಯೂನಿಫಾರ್ಮ್ಗಳು (WebGL1/ES 2.0) | ಯೂನಿಫಾರ್ಮ್ ಬಫರ್ ಆಬ್ಜೆಕ್ಟ್ಸ್ (WebGL2/ES 3.0) |
|---|---|---|
| ಡೇಟಾ ವರ್ಗಾವಣೆ ವಿಧಾನ | ಪ್ರತಿ ಯೂನಿಫಾರ್ಮ್ಗೆ ವೈಯಕ್ತಿಕ API ಕರೆಗಳು (ಉದಾ., gl.uniformMatrix4fv, gl.uniform3fv) |
ಗುಂಪು ಮಾಡಿದ ಡೇಟಾವನ್ನು ಬಫರ್ಗೆ ಅಪ್ಲೋಡ್ ಮಾಡಲಾಗುತ್ತದೆ (gl.bufferData, gl.bufferSubData) |
| ಸಿಪಿಯು-ಜಿಪಿಯು ಓವರ್ಹೆಡ್ | ಪ್ರತಿ ಯೂನಿಫಾರ್ಮ್ ಅಪ್ಡೇಟ್ಗೆ ಹೆಚ್ಚಿನ, ಆಗಾಗ್ಗೆ ಸಂದರ್ಭ ಬದಲಾವಣೆಗಳು. | ಸಂಪೂರ್ಣ ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ ಅಪ್ಡೇಟ್ಗಳಿಗೆ ಕಡಿಮೆ, ಒಂದೇ ಅಥವಾ ಕೆಲವು ಸಂದರ್ಭ ಬದಲಾವಣೆಗಳು. |
| ಪ್ರೋಗ್ರಾಂಗಳ ನಡುವೆ ಡೇಟಾ ಹಂಚಿಕೆ | ಕಷ್ಟ, ಸಾಮಾನ್ಯವಾಗಿ ಪ್ರತಿ ಶೇಡರ್ ಪ್ರೋಗ್ರಾಂಗೆ ಒಂದೇ ಡೇಟಾವನ್ನು ಮರು-ಅಪ್ಲೋಡ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ. | ಸುಲಭ ಮತ್ತು ದಕ್ಷ; ಒಂದೇ UBO ಅನ್ನು ಏಕಕಾಲದಲ್ಲಿ ಅನೇಕ ಪ್ರೋಗ್ರಾಂಗಳಿಗೆ ಬಂಧಿಸಬಹುದು. |
| ಮೆಮೊರಿ ಫುಟ್ಪ್ರಿಂಟ್ | ವಿಭಿನ್ನ ಪ್ರೋಗ್ರಾಂಗಳಿಗೆ ಪುನರಾವರ್ತಿತ ಡೇಟಾ ವರ್ಗಾವಣೆಗಳಿಂದಾಗಿ ಸಂಭಾವ್ಯವಾಗಿ ಹೆಚ್ಚು. | ಒಂದೇ ಬಫರ್ನಲ್ಲಿ ಡೇಟಾದ ಹಂಚಿಕೆ ಮತ್ತು ಆಪ್ಟಿಮೈಸ್ಡ್ ಪ್ಯಾಕಿಂಗ್ನಿಂದಾಗಿ ಕಡಿಮೆ. |
| ಸೆಟಪ್ ಸಂಕೀರ್ಣತೆ | ಕೆಲವು ಯೂನಿಫಾರ್ಮ್ಗಳೊಂದಿಗೆ ಅತ್ಯಂತ ಮೂಲಭೂತ ದೃಶ್ಯಗಳಿಗೆ ಸರಳ. | ಹೆಚ್ಚು ಆರಂಭಿಕ ಸೆಟಪ್ ಅಗತ್ಯವಿದೆ (ಬಫರ್ ರಚನೆ, ಲೇಔಟ್ ಹೊಂದಾಣಿಕೆ), ಆದರೆ ಅನೇಕ ಹಂಚಿದ ಯೂನಿಫಾರ್ಮ್ಗಳೊಂದಿಗೆ ಸಂಕೀರ್ಣ ದೃಶ್ಯಗಳಿಗೆ ಸರಳ. |
| ಶೇಡರ್ ಆವೃತ್ತಿಯ ಅವಶ್ಯಕತೆ | #version 100 es (WebGL1) |
#version 300 es (WebGL2) |
| ಸಾಮಾನ್ಯ ಬಳಕೆಯ ಪ್ರಕರಣಗಳು | ಪ್ರತಿ-ವಸ್ತುವಿನ ವಿಶಿಷ್ಟ ಡೇಟಾ (ಉದಾ., ಒಂದೇ ವಸ್ತುವಿಗೆ ಮಾಡೆಲ್ ಮ್ಯಾಟ್ರಿಕ್ಸ್), ಸರಳ ದೃಶ್ಯ ಪ್ಯಾರಾಮೀಟರ್ಗಳು. | ಜಾಗತಿಕ ದೃಶ್ಯ ಡೇಟಾ (ಕ್ಯಾಮರಾ ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳು, ಬೆಳಕಿನ ಪಟ್ಟಿಗಳು), ಹಂಚಿದ ವಸ್ತು ಗುಣಲಕ್ಷಣಗಳು, ಇನ್ಸ್ಟನ್ಸ್ಡ್ ಡೇಟಾ. |
UBOಗಳು ಸ್ಟ್ಯಾಂಡರ್ಡ್ ಯೂನಿಫಾರ್ಮ್ಗಳನ್ನು ಸಂಪೂರ್ಣವಾಗಿ ಬದಲಾಯಿಸುವುದಿಲ್ಲ ಎಂಬುದನ್ನು ಗಮನಿಸುವುದು ಮುಖ್ಯ. ನೀವು ಆಗಾಗ್ಗೆ ಎರಡರ ಸಂಯೋಜನೆಯನ್ನು ಬಳಸುತ್ತೀರಿ: ಜಾಗತಿಕವಾಗಿ ಹಂಚಿದ ಅಥವಾ ಆಗಾಗ್ಗೆ ನವೀಕರಿಸಲಾಗುವ ದೊಡ್ಡ ಡೇಟಾ ಬ್ಲಾಕ್ಗಳಿಗೆ UBOಗಳು, ಮತ್ತು ನಿರ್ದಿಷ್ಟ ಡ್ರಾ ಕರೆ ಅಥವಾ ವಸ್ತುವಿಗೆ ನಿಜವಾಗಿಯೂ ವಿಶಿಷ್ಟವಾದ ಮತ್ತು UBO ಓವರ್ಹೆಡ್ ಅನ್ನು ಸಮರ್ಥಿಸದ ಡೇಟಾಗೆ ಸ್ಟ್ಯಾಂಡರ್ಡ್ ಯೂನಿಫಾರ್ಮ್ಗಳು.
ಆಳವಾಗಿ ಇಳಿಯುವುದು: UBOಗಳು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತವೆ
UBOಗಳನ್ನು ಪರಿಣಾಮಕಾರಿಯಾಗಿ ಕಾರ್ಯಗತಗೊಳಿಸಲು ಆಧಾರವಾಗಿರುವ ಕಾರ್ಯವಿಧಾನಗಳನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳುವ ಅಗತ್ಯವಿದೆ, ವಿಶೇಷವಾಗಿ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ ಸಿಸ್ಟಮ್ ಮತ್ತು ನಿರ್ಣಾಯಕ ಡೇಟಾ ಲೇಔಟ್ ನಿಯಮಗಳು.
ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ ಸಿಸ್ಟಮ್
UBO ಕಾರ್ಯನಿರ್ವಹಣೆಯ ಹೃದಯದಲ್ಲಿ ಹೊಂದಿಕೊಳ್ಳುವ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ ಸಿಸ್ಟಮ್ ಇದೆ. ಜಿಪಿಯು ಸೂಚ್ಯಂಕಿತ "ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ಗಳ" (ಅಥವಾ "ಬೈಂಡಿಂಗ್ ಸೂಚ್ಯಂಕಗಳು" ಅಥವಾ "ಯೂನಿಫಾರ್ಮ್ ಬಫರ್ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ಗಳು") ಒಂದು ಸೆಟ್ ಅನ್ನು ನಿರ್ವಹಿಸುತ್ತದೆ, ಪ್ರತಿಯೊಂದೂ UBO ಗೆ ಉಲ್ಲೇಖವನ್ನು ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಬಹುದು. ಈ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ಗಳು ನಿಮ್ಮ UBOಗಳನ್ನು ಪ್ಲಗ್ ಮಾಡಬಹುದಾದ ಸಾರ್ವತ್ರಿಕ ಸ್ಲಾಟ್ಗಳಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತವೆ.
ಡೆವಲಪರ್ ಆಗಿ, ನಿಮ್ಮ ಡೇಟಾವನ್ನು ನಿಮ್ಮ ಶೇಡರ್ಗಳಿಗೆ ಸಂಪರ್ಕಿಸಲು ಸ್ಪಷ್ಟ ಮೂರು-ಹಂತದ ಪ್ರಕ್ರಿಯೆಗೆ ನೀವು ಜವಾಬ್ದಾರರಾಗಿರುತ್ತೀರಿ:
- UBO ಅನ್ನು ರಚಿಸಿ ಮತ್ತು ಭರ್ತಿ ಮಾಡಿ: ನೀವು ಜಿಪಿಯುನಲ್ಲಿ ಬಫರ್ ಆಬ್ಜೆಕ್ಟ್ ಅನ್ನು ಹಂಚಿಕೆ ಮಾಡುತ್ತೀರಿ (
gl.createBuffer()) ಮತ್ತು ಅದನ್ನು ಸಿಪಿಯುನಿಂದ ನಿಮ್ಮ ಯೂನಿಫಾರ್ಮ್ ಡೇಟಾದೊಂದಿಗೆ ಭರ್ತಿ ಮಾಡುತ್ತೀರಿ (gl.bufferData()ಅಥವಾgl.bufferSubData()). ಈ UBO ಕೇವಲ ಕಚ್ಚಾ ಡೇಟಾವನ್ನು ಹಿಡಿದಿರುವ ಮೆಮೊರಿಯ ಬ್ಲಾಕ್ ಆಗಿದೆ. - UBO ಅನ್ನು ಜಾಗತಿಕ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ಗೆ ಬಂಧಿಸಿ: ನೀವು ರಚಿಸಿದ UBO ಅನ್ನು ನಿರ್ದಿಷ್ಟ ಸಂಖ್ಯಾತ್ಮಕ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ನೊಂದಿಗೆ (ಉದಾ., 0, 1, 2, ಇತ್ಯಾದಿ)
gl.bindBufferBase(gl.UNIFORM_BUFFER, bindingPointIndex, uboObject)ಬಳಸಿ ಅಥವಾ ಭಾಗಶಃ ಬಂಧನಗಳಿಗಾಗಿgl.bindBufferRange()ಬಳಸಿ ಸಂಯೋಜಿಸುತ್ತೀರಿ. ಇದು UBO ಅನ್ನು ಆ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ ಮೂಲಕ ಜಾಗತಿಕವಾಗಿ ಪ್ರವೇಶಿಸುವಂತೆ ಮಾಡುತ್ತದೆ. - ಶೇಡರ್ ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ ಅನ್ನು ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ಗೆ ಸಂಪರ್ಕಿಸಿ: ನಿಮ್ಮ ಶೇಡರ್ನಲ್ಲಿ, ನೀವು ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ ಅನ್ನು ಘೋಷಿಸುತ್ತೀರಿ, ಮತ್ತು ನಂತರ, ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ನಲ್ಲಿ, ನೀವು ಆ ನಿರ್ದಿಷ್ಟ ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ ಅನ್ನು (ಶೇಡರ್ನಲ್ಲಿ ಅದರ ಹೆಸರಿನಿಂದ ಗುರುತಿಸಲಾಗಿದೆ) ಅದೇ ಸಂಖ್ಯಾತ್ಮಕ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ಗೆ
gl.uniformBlockBinding(shaderProgram, uniformBlockIndex, bindingPointIndex)ಬಳಸಿ ಲಿಂಕ್ ಮಾಡುತ್ತೀರಿ.
ಈ ಬೇರ್ಪಡಿಸುವಿಕೆ ಶಕ್ತಿಯುತವಾಗಿದೆ: *ಶೇಡರ್ ಪ್ರೋಗ್ರಾಂ* ಅದು ಯಾವ ನಿರ್ದಿಷ್ಟ UBO ಅನ್ನು ಬಳಸುತ್ತಿದೆ ಎಂದು ನೇರವಾಗಿ ತಿಳಿದಿರುವುದಿಲ್ಲ; ಅದಕ್ಕೆ ಕೇವಲ "ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ X" ನಿಂದ ಡೇಟಾ ಬೇಕು ಎಂದು ತಿಳಿದಿರುತ್ತದೆ. ನೀವು ನಂತರ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ X ಗೆ ನಿಯೋಜಿಸಲಾದ UBOಗಳನ್ನು (ಅಥವಾ UBOಗಳ ಭಾಗಗಳನ್ನು ಸಹ) ಶೇಡರ್ಗಳನ್ನು ಮರುಕಂಪೈಲ್ ಮಾಡದೆ ಅಥವಾ ಮರುಲಿಂಕ್ ಮಾಡದೆ ಕ್ರಿಯಾತ್ಮಕವಾಗಿ ಬದಲಾಯಿಸಬಹುದು, ಇದು ಕ್ರಿಯಾತ್ಮಕ ದೃಶ್ಯ ಅಪ್ಡೇಟ್ಗಳು ಅಥವಾ ಬಹು-ಪಾಸ್ ರೆಂಡರಿಂಗ್ಗೆ ಅಪಾರ ನಮ್ಯತೆಯನ್ನು ನೀಡುತ್ತದೆ. ಲಭ್ಯವಿರುವ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ಗಳ ಸಂಖ್ಯೆ ಸಾಮಾನ್ಯವಾಗಿ ಸೀಮಿತವಾಗಿದೆ ಆದರೆ ಹೆಚ್ಚಿನ ಅಪ್ಲಿಕೇಶನ್ಗಳಿಗೆ ಸಾಕಾಗುತ್ತದೆ (gl.MAX_UNIFORM_BUFFER_BINDINGS ಅನ್ನು ಪ್ರಶ್ನಿಸಿ).
ಸ್ಟ್ಯಾಂಡರ್ಡ್ ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ಗಳು
ನಿಮ್ಮ WebGL2 ಗಾಗಿ GLSL (ಗ್ರಾಫಿಕ್ಸ್ ಲೈಬ್ರರಿ ಶೇಡಿಂಗ್ ಲ್ಯಾಂಗ್ವೇಜ್) ಶೇಡರ್ಗಳಲ್ಲಿ, ನೀವು uniform ಕೀವರ್ಡ್ ಬಳಸಿ ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ಗಳನ್ನು ಘೋಷಿಸುತ್ತೀರಿ, ನಂತರ ಬ್ಲಾಕ್ ಹೆಸರು, ಮತ್ತು ನಂತರ ಕರ್ಲಿ ಬ್ರೇಸ್ಗಳೊಳಗೆ ವೇರಿಯಬಲ್ಗಳು. ನೀವು ಲೇಔಟ್ ಕ್ವಾಲಿಫೈಯರ್ ಅನ್ನು ಸಹ ನಿರ್ದಿಷ್ಟಪಡಿಸುತ್ತೀರಿ, ಸಾಮಾನ್ಯವಾಗಿ std140, ಇದು ಡೇಟಾವನ್ನು ಬಫರ್ನಲ್ಲಿ ಹೇಗೆ ಪ್ಯಾಕ್ ಮಾಡಲಾಗಿದೆ ಎಂಬುದನ್ನು ನಿರ್ದೇಶಿಸುತ್ತದೆ. ನಿಮ್ಮ ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್-ಬದಿಯ ಡೇಟಾವು ಜಿಪಿಯುನ ನಿರೀಕ್ಷೆಗಳಿಗೆ ಹೊಂದಿಕೆಯಾಗುವುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಲು ಈ ಲೇಔಟ್ ಕ್ವಾಲಿಫೈಯರ್ ಸಂಪೂರ್ಣವಾಗಿ ನಿರ್ಣಾಯಕವಾಗಿದೆ.
#version 300 es
layout (std140) uniform CameraMatrices {
mat4 projection;
mat4 view;
vec3 cameraPosition;
float exposure;
} CameraData;
// ... rest of your shader code ...
ಈ ಉದಾಹರಣೆಯಲ್ಲಿ:
layout (std140): ಇದು ಲೇಔಟ್ ಕ್ವಾಲಿಫೈಯರ್. ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ನ ಸದಸ್ಯರನ್ನು ಮೆಮೊರಿಯಲ್ಲಿ ಹೇಗೆ ಜೋಡಿಸಲಾಗಿದೆ ಮತ್ತು ಅಂತರ ಮಾಡಲಾಗಿದೆ ಎಂಬುದನ್ನು ವ್ಯಾಖ್ಯಾನಿಸಲು ಇದು ನಿರ್ಣಾಯಕವಾಗಿದೆ. WebGL2std140ಗೆ ಬೆಂಬಲವನ್ನು ಕಡ್ಡಾಯಗೊಳಿಸುತ್ತದೆ.sharedಅಥವಾpackedನಂತಹ ಇತರ ಲೇಔಟ್ಗಳು ಡೆಸ್ಕ್ಟಾಪ್ OpenGL ನಲ್ಲಿ ಅಸ್ತಿತ್ವದಲ್ಲಿವೆ ಆದರೆ WebGL2/ES 3.0 ನಲ್ಲಿ ಖಾತರಿಯಿಲ್ಲ.uniform CameraMatrices: ಇದುCameraMatricesಹೆಸರಿನ ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ ಅನ್ನು ಘೋಷಿಸುತ್ತದೆ. ಇದು ನೀವು ಶೇಡರ್ ಪ್ರೋಗ್ರಾಂನಲ್ಲಿ ಬ್ಲಾಕ್ ಅನ್ನು ಗುರುತಿಸಲು ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ನಲ್ಲಿ (gl.getUniformBlockIndexನೊಂದಿಗೆ) ಬಳಸುವ ಸ್ಟ್ರಿಂಗ್ ಹೆಸರು.mat4 projection;,mat4 view;,vec3 cameraPosition;,float exposure;: ಇವು ಬ್ಲಾಕ್ನಲ್ಲಿರುವ ಯೂನಿಫಾರ್ಮ್ ವೇರಿಯಬಲ್ಗಳು. ಅವು ಶೇಡರ್ನಲ್ಲಿ ಸಾಮಾನ್ಯ ಯೂನಿಫಾರ್ಮ್ಗಳಂತೆ ವರ್ತಿಸುತ್ತವೆ, ಆದರೆ ಅವುಗಳ ಡೇಟಾ ಮೂಲವು UBO ಆಗಿದೆ.} CameraData;: ಇದು ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ಗೆ ಐಚ್ಛಿಕ *ಇನ್ಸ್ಟನ್ಸ್ ಹೆಸರು*. ನೀವು ಅದನ್ನು ಬಿಟ್ಟರೆ, ಬ್ಲಾಕ್ ಹೆಸರು (CameraMatrices) ಬ್ಲಾಕ್ ಹೆಸರು ಮತ್ತು ಇನ್ಸ್ಟನ್ಸ್ ಹೆಸರು ಎರಡರಂತೆಯೂ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ. ಸ್ಪಷ್ಟತೆ ಮತ್ತು ಸ್ಥಿರತೆಗಾಗಿ ಇನ್ಸ್ಟನ್ಸ್ ಹೆಸರನ್ನು ಒದಗಿಸುವುದು ಸಾಮಾನ್ಯವಾಗಿ ಉತ್ತಮ ಅಭ್ಯಾಸವಾಗಿದೆ, ವಿಶೇಷವಾಗಿ ನೀವು ಒಂದೇ ಪ್ರಕಾರದ ಅನೇಕ ಬ್ಲಾಕ್ಗಳನ್ನು ಹೊಂದಿರುವಾಗ. ಶೇಡರ್ನಲ್ಲಿ ಸದಸ್ಯರನ್ನು ಪ್ರವೇಶಿಸುವಾಗ ಇನ್ಸ್ಟನ್ಸ್ ಹೆಸರನ್ನು ಬಳಸಲಾಗುತ್ತದೆ (ಉದಾ.,CameraData.projection).
ಡೇಟಾ ಲೇಔಟ್ ಮತ್ತು ಅಲೈನ್ಮೆಂಟ್ ಅವಶ್ಯಕತೆಗಳು
ಇದು ಬಹುಶಃ UBOಗಳ ಅತ್ಯಂತ ನಿರ್ಣಾಯಕ ಮತ್ತು ಆಗಾಗ್ಗೆ ತಪ್ಪಾಗಿ ಅರ್ಥೈಸಿಕೊಳ್ಳುವ ಅಂಶವಾಗಿದೆ. ದಕ್ಷ ಪ್ರವೇಶವನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಲು ಜಿಪಿಯುಗೆ ಬಫರ್ಗಳೊಳಗಿನ ಡೇಟಾವನ್ನು ನಿರ್ದಿಷ್ಟ ಅಲೈನ್ಮೆಂಟ್ ನಿಯಮಗಳ ಪ್ರಕಾರ ಹಾಕುವ ಅಗತ್ಯವಿದೆ. WebGL2 ಗಾಗಿ, ಡೀಫಾಲ್ಟ್ ಮತ್ತು ಸಾಮಾನ್ಯವಾಗಿ ಬಳಸುವ ಲೇಔಟ್ std140 ಆಗಿದೆ. ನಿಮ್ಮ ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ ಡೇಟಾ ರಚನೆಯು (ಉದಾ., Float32Array) ಪ್ಯಾಡಿಂಗ್ ಮತ್ತು ಅಲೈನ್ಮೆಂಟ್ಗಾಗಿ std140 ನಿಯಮಗಳಿಗೆ ನಿಖರವಾಗಿ ಹೊಂದಿಕೆಯಾಗದಿದ್ದರೆ, ನಿಮ್ಮ ಶೇಡರ್ಗಳು ತಪ್ಪಾದ ಅಥವಾ ಭ್ರಷ್ಟ ಡೇಟಾವನ್ನು ಓದುತ್ತವೆ, ಇದು ದೃಶ್ಯ ದೋಷಗಳು ಅಥವಾ ಕ್ರ್ಯಾಶ್ಗಳಿಗೆ ಕಾರಣವಾಗುತ್ತದೆ.
std140 ಲೇಔಟ್ ನಿಯಮಗಳು ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ನೊಳಗಿನ ಪ್ರತಿಯೊಂದು ಸದಸ್ಯರ ಅಲೈನ್ಮೆಂಟ್ ಮತ್ತು ಬ್ಲಾಕ್ನ ಒಟ್ಟಾರೆ ಗಾತ್ರವನ್ನು ನಿರ್ದೇಶಿಸುತ್ತವೆ. ಈ ನಿಯಮಗಳು ವಿಭಿನ್ನ ಹಾರ್ಡ್ವೇರ್ ಮತ್ತು ಡ್ರೈವರ್ಗಳಾದ್ಯಂತ ಸ್ಥಿರತೆಯನ್ನು ಖಚಿತಪಡಿಸುತ್ತವೆ, ಆದರೆ ಅವುಗಳಿಗೆ ಎಚ್ಚರಿಕೆಯ ಹಸ್ತಚಾಲಿತ ಲೆಕ್ಕಾಚಾರ ಅಥವಾ ಸಹಾಯಕ ಲೈಬ್ರರಿಗಳ ಬಳಕೆಯ ಅಗತ್ಯವಿರುತ್ತದೆ. ಇಲ್ಲಿ ಅತ್ಯಂತ ಪ್ರಮುಖ ನಿಯಮಗಳ ಸಾರಾಂಶವಿದೆ, ಮೂಲ ಸ್ಕೇಲಾರ್ ಗಾತ್ರ (N) 4 ಬೈಟ್ಗಳು (ಒಂದು float, int, ಅಥವಾ bool ಗಾಗಿ) ಎಂದು ಭಾವಿಸಿ:
-
ಸ್ಕೇಲಾರ್ ಪ್ರಕಾರಗಳು (
float,int,bool):- ಬೇಸ್ ಅಲೈನ್ಮೆಂಟ್: N (4 ಬೈಟ್ಗಳು).
- ಗಾತ್ರ: N (4 ಬೈಟ್ಗಳು).
-
ವೆಕ್ಟರ್ ಪ್ರಕಾರಗಳು (
vec2,vec3,vec4):vec2: ಬೇಸ್ ಅಲೈನ್ಮೆಂಟ್: 2N (8 ಬೈಟ್ಗಳು). ಗಾತ್ರ: 2N (8 ಬೈಟ್ಗಳು).vec3: ಬೇಸ್ ಅಲೈನ್ಮೆಂಟ್: 4N (16 ಬೈಟ್ಗಳು). ಗಾತ್ರ: 3N (12 ಬೈಟ್ಗಳು). ಇದು ಬಹಳ ಸಾಮಾನ್ಯವಾದ ಗೊಂದಲದ ಬಿಂದು;vec3ಅನ್ನುvec4ನಂತೆ ಜೋಡಿಸಲಾಗುತ್ತದೆ, ಆದರೆ ಕೇವಲ 12 ಬೈಟ್ಗಳನ್ನು ಆಕ್ರಮಿಸುತ್ತದೆ. ಆದ್ದರಿಂದ, ಇದು ಯಾವಾಗಲೂ 16-ಬೈಟ್ ಗಡಿಯಲ್ಲಿ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ.vec4: ಬೇಸ್ ಅಲೈನ್ಮೆಂಟ್: 4N (16 ಬೈಟ್ಗಳು). ಗಾತ್ರ: 4N (16 ಬೈಟ್ಗಳು).
-
ಅರೇಗಳು:
- ಅರೇಯ ಪ್ರತಿಯೊಂದು ಅಂಶವು (ಅದರ ಪ್ರಕಾರವನ್ನು ಲೆಕ್ಕಿಸದೆ, ಒಂದೇ
floatಕೂಡ)vec4(16 ಬೈಟ್ಗಳು) ನ ಬೇಸ್ ಅಲೈನ್ಮೆಂಟ್ಗೆ ಅಥವಾ ತನ್ನದೇ ಆದ ಬೇಸ್ ಅಲೈನ್ಮೆಂಟ್ಗೆ, ಯಾವುದು ದೊಡ್ಡದೋ ಅದಕ್ಕೆ ಜೋಡಿಸಲ್ಪಡುತ್ತದೆ. ಪ್ರಾಯೋಗಿಕ ಉದ್ದೇಶಗಳಿಗಾಗಿ, ಪ್ರತಿ ಅರೇ ಅಂಶಕ್ಕೆ 16-ಬೈಟ್ ಅಲೈನ್ಮೆಂಟ್ ಅನ್ನು ಊಹಿಸಿ. - ಉದಾಹರಣೆಗೆ,
floatಗಳ ಅರೇ (float[]) ಪ್ರತಿ ಫ್ಲೋಟ್ ಅಂಶವು 4 ಬೈಟ್ಗಳನ್ನು ಆಕ್ರಮಿಸುತ್ತದೆ ಆದರೆ 16 ಬೈಟ್ಗಳಿಗೆ ಜೋಡಿಸಲ್ಪಡುತ್ತದೆ. ಇದರರ್ಥ ಅರೇಯೊಳಗಿನ ಪ್ರತಿ ಫ್ಲೋಟ್ ನಂತರ 12 ಬೈಟ್ಗಳ ಪ್ಯಾಡಿಂಗ್ ಇರುತ್ತದೆ. - ಸ್ಟ್ರೈಡ್ (ಒಂದು ಅಂಶದ ಪ್ರಾರಂಭ ಮತ್ತು ಮುಂದಿನದರ ಪ್ರಾರಂಭದ ನಡುವಿನ ಅಂತರ) ಅನ್ನು 16 ಬೈಟ್ಗಳ ಗುಣಕಕ್ಕೆ ದುಂಡಾಗಿಸಲಾಗುತ್ತದೆ.
- ಅರೇಯ ಪ್ರತಿಯೊಂದು ಅಂಶವು (ಅದರ ಪ್ರಕಾರವನ್ನು ಲೆಕ್ಕಿಸದೆ, ಒಂದೇ
-
ರಚನೆಗಳು (
struct):- ರಚನೆಯ ಬೇಸ್ ಅಲೈನ್ಮೆಂಟ್ ಅದರ ಯಾವುದೇ ಸದಸ್ಯರ ಅತಿದೊಡ್ಡ ಬೇಸ್ ಅಲೈನ್ಮೆಂಟ್ ಆಗಿದೆ, ಇದನ್ನು 16 ಬೈಟ್ಗಳ ಗುಣಕಕ್ಕೆ ದುಂಡಾಗಿಸಲಾಗುತ್ತದೆ.
- ರಚನೆಯೊಳಗಿನ ಪ್ರತಿಯೊಂದು ಸದಸ್ಯನು ರಚನೆಯ ಪ್ರಾರಂಭಕ್ಕೆ ಸಂಬಂಧಿಸಿದಂತೆ ತನ್ನದೇ ಆದ ಅಲೈನ್ಮೆಂಟ್ ನಿಯಮಗಳನ್ನು ಅನುಸರಿಸುತ್ತಾನೆ.
- ರಚನೆಯ ಒಟ್ಟು ಗಾತ್ರವನ್ನು (ಅದರ ಪ್ರಾರಂಭದಿಂದ ಅದರ ಕೊನೆಯ ಸದಸ್ಯನ ಅಂತ್ಯದವರೆಗೆ) 16 ಬೈಟ್ಗಳ ಗುಣಕಕ್ಕೆ ದುಂಡಾಗಿಸಲಾಗುತ್ತದೆ. ಇದಕ್ಕೆ ರಚನೆಯ ಕೊನೆಯಲ್ಲಿ ಪ್ಯಾಡಿಂಗ್ ಅಗತ್ಯವಾಗಬಹುದು.
-
ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳು:
- ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳನ್ನು ವೆಕ್ಟರ್ಗಳ ಅರೇಗಳಾಗಿ ಪರಿಗಣಿಸಲಾಗುತ್ತದೆ. ಮ್ಯಾಟ್ರಿಕ್ಸ್ನ ಪ್ರತಿಯೊಂದು ಕಾಲಮ್ (ಇದು ವೆಕ್ಟರ್ ಆಗಿದೆ) ಅರೇ ಅಂಶ ನಿಯಮಗಳನ್ನು ಅನುಸರಿಸುತ್ತದೆ.
- ಒಂದು
mat4(4x4 ಮ್ಯಾಟ್ರಿಕ್ಸ್) ನಾಲ್ಕುvec4ಗಳ ಅರೇ ಆಗಿದೆ. ಪ್ರತಿಯೊಂದುvec416 ಬೈಟ್ಗಳಿಗೆ ಜೋಡಿಸಲ್ಪಟ್ಟಿದೆ. ಒಟ್ಟು ಗಾತ್ರ: 4 * 16 = 64 ಬೈಟ್ಗಳು. - ಒಂದು
mat3(3x3 ಮ್ಯಾಟ್ರಿಕ್ಸ್) ಮೂರುvec3ಗಳ ಅರೇ ಆಗಿದೆ. ಪ್ರತಿಯೊಂದುvec316 ಬೈಟ್ಗಳಿಗೆ ಜೋಡಿಸಲ್ಪಟ್ಟಿದೆ. ಒಟ್ಟು ಗಾತ್ರ: 3 * 16 = 48 ಬೈಟ್ಗಳು. - ಒಂದು
mat2(2x2 ಮ್ಯಾಟ್ರಿಕ್ಸ್) ಎರಡುvec2ಗಳ ಅರೇ ಆಗಿದೆ. ಪ್ರತಿಯೊಂದುvec28 ಬೈಟ್ಗಳಿಗೆ ಜೋಡಿಸಲ್ಪಟ್ಟಿದೆ, ಆದರೆ ಅರೇ ಅಂಶಗಳು 16 ಕ್ಕೆ ಜೋಡಿಸಲ್ಪಟ್ಟಿರುವುದರಿಂದ, ಪ್ರತಿಯೊಂದು ಕಾಲಮ್ ಪರಿಣಾಮಕಾರಿಯಾಗಿ 16-ಬೈಟ್ ಗಡಿಯಲ್ಲಿ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ. ಒಟ್ಟು ಗಾತ್ರ: 2 * 16 = 32 ಬೈಟ್ಗಳು.
ರಚನೆಗಳು ಮತ್ತು ಅರೇಗಳಿಗೆ ಪ್ರಾಯೋಗಿಕ ಪರಿಣಾಮಗಳು
ಒಂದು ಉದಾಹರಣೆಯೊಂದಿಗೆ ವಿವರಿಸೋಣ. ಈ ಶೇಡರ್ ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ ಅನ್ನು ಪರಿಗಣಿಸಿ:
layout (std140) uniform LightInfo {
vec3 lightPosition;
float lightIntensity;
vec4 lightColor;
mat4 lightTransform;
float attenuationFactors[3];
} LightData;
ಮೆಮೊರಿಯಲ್ಲಿ ಇದನ್ನು ಹೇಗೆ ಹಾಕಲಾಗುತ್ತದೆ ಎಂಬುದು ಇಲ್ಲಿದೆ, ಬೈಟ್ಗಳಲ್ಲಿ (ಪ್ರತಿ ಫ್ಲೋಟ್ಗೆ 4 ಬೈಟ್ಗಳು ಎಂದು ಭಾವಿಸಿ):
- ಆಫ್ಸೆಟ್ 0:
vec3 lightPosition;- 16-ಬೈಟ್ ಗಡಿಯಲ್ಲಿ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ (0 ಮಾನ್ಯವಾಗಿದೆ).
- 12 ಬೈಟ್ಗಳನ್ನು ಆಕ್ರಮಿಸುತ್ತದೆ (3 ಫ್ಲೋಟ್ಗಳು * 4 ಬೈಟ್ಗಳು/ಫ್ಲೋಟ್).
- ಅಲೈನ್ಮೆಂಟ್ಗಾಗಿ ಪರಿಣಾಮಕಾರಿ ಗಾತ್ರ: 16 ಬೈಟ್ಗಳು.
- ಆಫ್ಸೆಟ್ 16:
float lightIntensity;- 4-ಬೈಟ್ ಗಡಿಯಲ್ಲಿ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ.
lightPositionಪರಿಣಾಮಕಾರಿಯಾಗಿ 16 ಬೈಟ್ಗಳನ್ನು ಸೇವಿಸಿದ್ದರಿಂದ,lightIntensityಬೈಟ್ 16 ರಿಂದ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ. - 4 ಬೈಟ್ಗಳನ್ನು ಆಕ್ರಮಿಸುತ್ತದೆ.
- 4-ಬೈಟ್ ಗಡಿಯಲ್ಲಿ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ.
- ಆಫ್ಸೆಟ್ 20-31: 12 ಬೈಟ್ಗಳ ಪ್ಯಾಡಿಂಗ್. ಮುಂದಿನ ಸದಸ್ಯನನ್ನು (
vec4) ಅದರ ಅಗತ್ಯವಿರುವ 16-ಬೈಟ್ ಅಲೈನ್ಮೆಂಟ್ಗೆ ತರಲು ಇದು ಅಗತ್ಯವಿದೆ. - ಆಫ್ಸೆಟ್ 32:
vec4 lightColor;- 16-ಬೈಟ್ ಗಡಿಯಲ್ಲಿ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ (32 ಮಾನ್ಯವಾಗಿದೆ).
- 16 ಬೈಟ್ಗಳನ್ನು ಆಕ್ರಮಿಸುತ್ತದೆ (4 ಫ್ಲೋಟ್ಗಳು * 4 ಬೈಟ್ಗಳು/ಫ್ಲೋಟ್).
- ಆಫ್ಸೆಟ್ 48:
mat4 lightTransform;- 16-ಬೈಟ್ ಗಡಿಯಲ್ಲಿ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ (48 ಮಾನ್ಯವಾಗಿದೆ).
- 64 ಬೈಟ್ಗಳನ್ನು ಆಕ್ರಮಿಸುತ್ತದೆ (4
vec4ಕಾಲಮ್ಗಳು * 16 ಬೈಟ್ಗಳು/ಕಾಲಮ್).
- ಆಫ್ಸೆಟ್ 112:
float attenuationFactors[3];(ಮೂರು ಫ್ಲೋಟ್ಗಳ ಅರೇ)- ಪ್ರತಿಯೊಂದು ಅಂಶವನ್ನು 16 ಬೈಟ್ಗಳಿಗೆ ಜೋಡಿಸಬೇಕು.
attenuationFactors[0]: 112 ರಿಂದ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ. 4 ಬೈಟ್ಗಳನ್ನು ಆಕ್ರಮಿಸುತ್ತದೆ, ಪರಿಣಾಮಕಾರಿಯಾಗಿ 16 ಬೈಟ್ಗಳನ್ನು ಸೇವಿಸುತ್ತದೆ.attenuationFactors[1]: 128 ರಿಂದ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ (112 + 16). 4 ಬೈಟ್ಗಳನ್ನು ಆಕ್ರಮಿಸುತ್ತದೆ, ಪರಿಣಾಮಕಾರಿಯಾಗಿ 16 ಬೈಟ್ಗಳನ್ನು ಸೇವಿಸುತ್ತದೆ.attenuationFactors[2]: 144 ರಿಂದ ಪ್ರಾರಂಭವಾಗುತ್ತದೆ (128 + 16). 4 ಬೈಟ್ಗಳನ್ನು ಆಕ್ರಮಿಸುತ್ತದೆ, ಪರಿಣಾಮಕಾರಿಯಾಗಿ 16 ಬೈಟ್ಗಳನ್ನು ಸೇವಿಸುತ್ತದೆ.
- ಆಫ್ಸೆಟ್ 160: ಬ್ಲಾಕ್ನ ಅಂತ್ಯ.
LightInfoಬ್ಲಾಕ್ನ ಒಟ್ಟು ಗಾತ್ರ 160 ಬೈಟ್ಗಳಾಗಿರುತ್ತದೆ.
ನೀವು ನಂತರ ಈ ನಿಖರವಾದ ಗಾತ್ರದ (160 ಬೈಟ್ಗಳು / 4 ಬೈಟ್ಗಳು ಪ್ರತಿ ಫ್ಲೋಟ್ಗೆ = 40 ಫ್ಲೋಟ್ಗಳು) ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ Float32Array (ಅಥವಾ ಅಂತಹುದೇ ಟೈಪ್ ಮಾಡಿದ ಅರೇ) ಅನ್ನು ರಚಿಸಿ ಮತ್ತು ಅದನ್ನು ಎಚ್ಚರಿಕೆಯಿಂದ ಭರ್ತಿ ಮಾಡುತ್ತೀರಿ, ಅರೇಯಲ್ಲಿ ಅಂತರಗಳನ್ನು ಬಿಡುವ ಮೂಲಕ ಸರಿಯಾದ ಪ್ಯಾಡಿಂಗ್ ಅನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳುತ್ತೀರಿ. ಪರಿಕರಗಳು ಮತ್ತು ಲೈಬ್ರರಿಗಳು (WebGL-ನಿರ್ದಿಷ್ಟ ಉಪಯುಕ್ತತೆ ಲೈಬ್ರರಿಗಳಂತಹ) ಆಗಾಗ್ಗೆ ಇದಕ್ಕಾಗಿ ಸಹಾಯಕಗಳನ್ನು ಒದಗಿಸುತ್ತವೆ, ಆದರೆ ಡೀಬಗ್ ಮಾಡಲು ಅಥವಾ ಕಸ್ಟಮ್ ಲೇಔಟ್ಗಳಿಗಾಗಿ ಹಸ್ತಚಾಲಿತ ಲೆಕ್ಕಾಚಾರವು ಕೆಲವೊಮ್ಮೆ ಅಗತ್ಯವಾಗಿರುತ್ತದೆ. ಇಲ್ಲಿ ತಪ್ಪು ಲೆಕ್ಕಾಚಾರವು ದೋಷಗಳ ಸಾಮಾನ್ಯ ಮೂಲವಾಗಿದೆ!
WebGL2 ನಲ್ಲಿ UBOಗಳನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸುವುದು: ಒಂದು ಹಂತ-ಹಂತದ ಮಾರ್ಗದರ್ಶಿ
UBOಗಳ ಪ್ರಾಯೋಗಿಕ ಅನುಷ್ಠಾನವನ್ನು ನೋಡೋಣ. ನಾವು ಸಾಮಾನ್ಯ ಸನ್ನಿವೇಶವನ್ನು ಬಳಸುತ್ತೇವೆ: ಒಂದು ದೃಶ್ಯದಲ್ಲಿನ ಅನೇಕ ಶೇಡರ್ಗಳಲ್ಲಿ ಹಂಚಿಕೊಳ್ಳಲು ಕ್ಯಾಮರಾ ಪ್ರೊಜೆಕ್ಷನ್ ಮತ್ತು ವ್ಯೂ ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳನ್ನು UBO ನಲ್ಲಿ ಸಂಗ್ರಹಿಸುವುದು.
ಶೇಡರ್-ಬದಿಯ ಘೋಷಣೆ
ಮೊದಲಿಗೆ, ನಿಮ್ಮ ವರ್ಟೆಕ್ಸ್ ಮತ್ತು ಫ್ರಾಗ್ಮೆಂಟ್ ಶೇಡರ್ಗಳಲ್ಲಿ (ಅಥವಾ ಈ ಯೂನಿಫಾರ್ಮ್ಗಳು ಎಲ್ಲಿ ಬೇಕಾದರೂ) ನಿಮ್ಮ ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ ಅನ್ನು ವ್ಯಾಖ್ಯಾನಿಸಿ. WebGL2 ಶೇಡರ್ಗಳಿಗಾಗಿ #version 300 es ನಿರ್ದೇಶನವನ್ನು ನೆನಪಿಡಿ.
ವರ್ಟೆಕ್ಸ್ ಶೇಡರ್ ಉದಾಹರಣೆ (shader.vert)
#version 300 es
layout (location = 0) in vec4 a_position;
layout (location = 1) in vec3 a_normal;
uniform mat4 u_modelMatrix; // This is a standard uniform, typically unique per object
// Declare the Uniform Buffer Object block
layout (std140) uniform CameraMatrices {
mat4 projection;
mat4 view;
vec3 cameraPosition; // Adding camera position for completeness
float _padding; // Padding to align to 16 bytes after vec3
} CameraData;
out vec3 v_normal;
out vec3 v_worldPosition;
void main() {
vec4 worldPosition = u_modelMatrix * a_position;
gl_Position = CameraData.projection * CameraData.view * worldPosition;
v_normal = mat3(u_modelMatrix) * a_normal;
v_worldPosition = worldPosition.xyz;
}
ಇಲ್ಲಿ, CameraData.projection ಮತ್ತು CameraData.view ಗಳನ್ನು ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ನಿಂದ ಪ್ರವೇಶಿಸಲಾಗುತ್ತದೆ. u_modelMatrix ಇನ್ನೂ ಒಂದು ಸ್ಟ್ಯಾಂಡರ್ಡ್ ಯೂನಿಫಾರ್ಮ್ ಆಗಿದೆ ಎಂಬುದನ್ನು ಗಮನಿಸಿ; UBOಗಳು ಹಂಚಿದ ಡೇಟಾ ಸಂಗ್ರಹಗಳಿಗೆ ಉತ್ತಮವಾಗಿವೆ, ಮತ್ತು ವೈಯಕ್ತಿಕ ಪ್ರತಿ-ವಸ್ತು ಯೂನಿಫಾರ್ಮ್ಗಳು (ಅಥವಾ ಪ್ರತಿ-ಇನ್ಸ್ಟನ್ಸ್ ಗುಣಲಕ್ಷಣಗಳು) ಪ್ರತಿ ವಸ್ತುವಿಗೆ ವಿಶಿಷ್ಟವಾದ ಗುಣಲಕ್ಷಣಗಳಿಗೆ ಇನ್ನೂ ಸಾಮಾನ್ಯವಾಗಿದೆ.
_padding ಮೇಲಿನ ಟಿಪ್ಪಣಿ: ಒಂದು vec3 (12 ಬೈಟ್ಗಳು) ನಂತರ ಒಂದು float (4 ಬೈಟ್ಗಳು) ಸಾಮಾನ್ಯವಾಗಿ ಬಿಗಿಯಾಗಿ ಪ್ಯಾಕ್ ಆಗುತ್ತದೆ. ಆದಾಗ್ಯೂ, ಮುಂದಿನ ಸದಸ್ಯ, ಉದಾಹರಣೆಗೆ, vec4 ಅಥವಾ ಇನ್ನೊಂದು mat4 ಆಗಿದ್ದರೆ, float std140 ಲೇಔಟ್ನಲ್ಲಿ 16-ಬೈಟ್ ಗಡಿಗೆ ಸ್ವಾಭಾವಿಕವಾಗಿ ಜೋಡಿಸದಿರಬಹುದು, ಇದು ಸಮಸ್ಯೆಗಳನ್ನು ಉಂಟುಮಾಡುತ್ತದೆ. ಸ್ಪಷ್ಟ ಪ್ಯಾಡಿಂಗ್ (float _padding;) ಕೆಲವೊಮ್ಮೆ ಸ್ಪಷ್ಟತೆಗಾಗಿ ಅಥವಾ ಅಲೈನ್ಮೆಂಟ್ ಅನ್ನು ಬಲವಂತಪಡಿಸಲು ಸೇರಿಸಲಾಗುತ್ತದೆ. ಈ ನಿರ್ದಿಷ್ಟ ಸಂದರ್ಭದಲ್ಲಿ, vec3 16-ಬೈಟ್ ಜೋಡಿಸಲ್ಪಟ್ಟಿದೆ, float 4-ಬೈಟ್ ಜೋಡಿಸಲ್ಪಟ್ಟಿದೆ, ಆದ್ದರಿಂದ cameraPosition (16 ಬೈಟ್ಗಳು) + _padding (4 ಬೈಟ್ಗಳು) ಸಂಪೂರ್ಣವಾಗಿ 20 ಬೈಟ್ಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ. ಒಂದು vec4 ಅನುಸರಿಸುತ್ತಿದ್ದರೆ, ಅದು 16-ಬೈಟ್ ಗಡಿಯಲ್ಲಿ, ಅಂದರೆ ಬೈಟ್ 32 ರಿಂದ ಪ್ರಾರಂಭವಾಗಬೇಕಾಗುತ್ತದೆ. ಬೈಟ್ 20 ರಿಂದ, ಅದು 12 ಬೈಟ್ಗಳ ಪ್ಯಾಡಿಂಗ್ ಅನ್ನು ಬಿಡುತ್ತದೆ. ಈ ಉದಾಹರಣೆಯು ಎಚ್ಚರಿಕೆಯ ಲೇಔಟ್ ಅಗತ್ಯವಿದೆ ಎಂದು ತೋರಿಸುತ್ತದೆ.
ಫ್ರಾಗ್ಮೆಂಟ್ ಶೇಡರ್ ಉದಾಹರಣೆ (shader.frag)
ಫ್ರಾಗ್ಮೆಂಟ್ ಶೇಡರ್ ನೇರವಾಗಿ ರೂಪಾಂತರಗಳಿಗಾಗಿ ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳನ್ನು ಬಳಸದಿದ್ದರೂ ಸಹ, ಅದಕ್ಕೆ ಕ್ಯಾಮರಾ-ಸಂಬಂಧಿತ ಡೇಟಾ (ಉದಾಹರಣೆಗೆ ಸ್ಪೆಕ್ಯುಲರ್ ಲೈಟಿಂಗ್ ಲೆಕ್ಕಾಚಾರಗಳಿಗಾಗಿ ಕ್ಯಾಮರಾ ಸ್ಥಾನ) ಬೇಕಾಗಬಹುದು ಅಥವಾ ಫ್ರಾಗ್ಮೆಂಟ್ ಶೇಡರ್ ಬಳಸುವ ವಸ್ತು ಗುಣಲಕ್ಷಣಗಳಿಗಾಗಿ ನೀವು ವಿಭಿನ್ನ UBO ಹೊಂದಿರಬಹುದು.
#version 300 es
precision highp float;
in vec3 v_normal;
in vec3 v_worldPosition;
uniform vec3 u_lightDirection; // Standard uniform for simplicity
uniform vec4 u_objectColor;
// Declare the same Uniform Buffer Object block here
layout (std140) uniform CameraMatrices {
mat4 projection;
mat4 view;
vec3 cameraPosition;
float _padding;
} CameraData;
out vec4 outColor;
void main() {
// Basic diffuse lighting using a standard uniform for light direction
float diffuse = max(dot(normalize(v_normal), normalize(u_lightDirection)), 0.0);
// Example: Using camera position from UBO for view direction
vec3 viewDirection = normalize(CameraData.cameraPosition - v_worldPosition);
// For a simple demo, we'll just use diffuse for output color
outColor = u_objectColor * diffuse;
}
ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್-ಬದಿಯ ಅನುಷ್ಠಾನ
ಈಗ, ಈ UBO ಅನ್ನು ನಿರ್ವಹಿಸಲು ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ ಕೋಡ್ ಅನ್ನು ನೋಡೋಣ. ನಾವು ಮ್ಯಾಟ್ರಿಕ್ಸ್ ಕಾರ್ಯಾಚರಣೆಗಳಿಗಾಗಿ ಜನಪ್ರಿಯ gl-matrix ಲೈಬ್ರರಿಯನ್ನು ಬಳಸುತ್ತೇವೆ.
// Assume 'gl' is your WebGL2RenderingContext, obtained from canvas.getContext('webgl2')
// Assume 'shaderProgram' is your linked WebGLProgram, obtained from createProgram(gl, vsSource, fsSource)
import { mat4, vec3 } from 'gl-matrix';
// --------------------------------------------------------------------------------
// Step 1: Create the UBO Buffer Object
// --------------------------------------------------------------------------------
const cameraUBO = gl.createBuffer();
gl.bindBuffer(gl.UNIFORM_BUFFER, cameraUBO);
// Determine the size needed for the UBO based on std140 layout:
// mat4: 16 floats (64 bytes)
// mat4: 16 floats (64 bytes)
// vec3: 3 floats (12 bytes), but aligned to 16 bytes
// float: 1 float (4 bytes)
// Total floats: 16 + 16 + 4 + 4 = 40 floats (considering padding for vec3 and float)
// In the shader: mat4 (64) + mat4 (64) + vec3 (16) + float (16) = 160 bytes
// Calculation:
// projection (mat4) = 64 bytes
// view (mat4) = 64 bytes
// cameraPosition (vec3) = 12 bytes + 4 bytes padding (to reach 16-byte boundary for next float) = 16 bytes
// exposure (float) = 4 bytes + 12 bytes padding (to end on 16-byte boundary) = 16 bytes
// Total = 64 + 64 + 16 + 16 = 160 bytes
const UBO_BYTE_SIZE = 160;
// Allocate memory on GPU. Use DYNAMIC_DRAW as camera matrices update every frame.
gl.bufferData(gl.UNIFORM_BUFFER, UBO_BYTE_SIZE, gl.DYNAMIC_DRAW);
gl.bindBuffer(gl.UNIFORM_BUFFER, null); // Unbind the UBO from the UNIFORM_BUFFER target
// --------------------------------------------------------------------------------
// Step 2: Define and Populate CPU-Side Data for the UBO
// --------------------------------------------------------------------------------
const projectionMatrix = mat4.create(); // Use gl-matrix for matrix operations
const viewMatrix = mat4.create();
const cameraPos = vec3.fromValues(0, 0, 5); // Initial camera position
const exposureValue = 1.0; // Example exposure value
// Create a Float32Array to hold the combined data.
// This must match the std140 layout exactly.
// Projection (16 floats), View (16 floats), CameraPosition (4 floats due to vec3+padding),
// Exposure (4 floats due to float+padding). Total: 16+16+4+4 = 40 floats.
const cameraMatricesData = new Float32Array(40);
// ... calculate your initial projection and view matrices ...
mat4.perspective(projectionMatrix, Math.PI / 4, gl.canvas.width / gl.canvas.height, 0.1, 100.0);
mat4.lookAt(viewMatrix, cameraPos, vec3.fromValues(0, 0, 0), vec3.fromValues(0, 1, 0));
// Copy data into the Float32Array, observing std140 offsets
cameraMatricesData.set(projectionMatrix, 0); // Offset 0 (16 floats)
cameraMatricesData.set(viewMatrix, 16); // Offset 16 (16 floats)
cameraMatricesData.set(cameraPos, 32); // Offset 32 (vec3, 3 floats). Next available is 32+3=35.
// There's 1 float of padding in the shader's vec3, so the next item starts at offset 36 in the Float32Array.
cameraMatricesData[35] = exposureValue; // Offset 35 (float). This is tricky. The float 'exposure' is at byte 140.
// 160 bytes / 4 bytes per float = 40 floats.
// `projection` takes 0-15.
// `view` takes 16-31.
// `cameraPosition` takes 32, 33, 34.
// The `_padding` for `vec3 cameraPosition` is at index 35.
// `exposure` is at index 36. This is where manual tracking is vital.
// Let's re-evaluate the padding carefully for `cameraPosition` and `exposure`
// shader: mat4 projection (64 bytes)
// shader: mat4 view (64 bytes)
// shader: vec3 cameraPosition (16 bytes aligned, 12 bytes used)
// shader: float _padding (4 bytes, fills out 16 bytes for vec3)
// shader: float exposure (16 bytes aligned, 4 bytes used)
// Total 64+64+16+16 = 160 bytes
// Float32Array Indices:
// projection: indices 0-15
// view: indices 16-31
// cameraPosition: indices 32-34 (3 floats for vec3)
// padding after cameraPosition: index 35 (1 float for the _padding in GLSL)
// exposure: index 36 (1 float)
// padding after exposure: indices 37-39 (3 floats for padding to make exposure take 16 bytes)
const OFFSET_PROJECTION = 0;
const OFFSET_VIEW = 16; // 16 floats * 4 bytes/float = 64 bytes offset
const OFFSET_CAMERA_POS = 32; // 32 floats * 4 bytes/float = 128 bytes offset
const OFFSET_EXPOSURE = 36; // (32 + 3 floats for vec3 + 1 float for _padding) * 4 bytes/float = 144 bytes offset
cameraMatricesData.set(projectionMatrix, OFFSET_PROJECTION);
cameraMatricesData.set(viewMatrix, OFFSET_VIEW);
cameraMatricesData.set(cameraPos, OFFSET_CAMERA_POS);
cameraMatricesData[OFFSET_EXPOSURE] = exposureValue;
// --------------------------------------------------------------------------------
// Step 3: Bind the UBO to a Binding Point (e.g., binding point 0)
// --------------------------------------------------------------------------------
const UBO_BINDING_POINT = 0; // Choose an available binding point index
gl.bindBufferBase(gl.UNIFORM_BUFFER, UBO_BINDING_POINT, cameraUBO);
// --------------------------------------------------------------------------------
// Step 4: Connect Shader Uniform Block to the Binding Point
// --------------------------------------------------------------------------------
// Get the index of the uniform block 'CameraMatrices' from your shader program
const cameraBlockIndex = gl.getUniformBlockIndex(shaderProgram, 'CameraMatrices');
// Associate the uniform block index with the UBO binding point
gl.uniformBlockBinding(shaderProgram, cameraBlockIndex, UBO_BINDING_POINT);
// Repeat for any other shader programs that use the 'CameraMatrices' uniform block.
// For example, if you had 'anotherShaderProgram':
// const anotherCameraBlockIndex = gl.getUniformBlockIndex(anotherShaderProgram, 'CameraMatrices');
// gl.uniformBlockBinding(anotherShaderProgram, anotherCameraBlockIndex, UBO_BINDING_POINT);
// --------------------------------------------------------------------------------
// Step 5: Update UBO Data (e.g., once per frame, or when camera moves)
// --------------------------------------------------------------------------------
function updateCameraUBO() {
// Recalculate projection/view if needed
mat4.perspective(projectionMatrix, Math.PI / 4, gl.canvas.width / gl.canvas.height, 0.1, 100.0);
// Example: Camera moving around the origin
const time = performance.now() * 0.001; // Current time in seconds
const radius = 5;
const camX = Math.sin(time * 0.5) * radius;
const camZ = Math.cos(time * 0.5) * radius;
vec3.set(cameraPos, camX, 2, camZ);
mat4.lookAt(viewMatrix, cameraPos, vec3.fromValues(0, 0, 0), vec3.fromValues(0, 1, 0));
// Update the CPU-side Float32Array with new data
cameraMatricesData.set(projectionMatrix, OFFSET_PROJECTION);
cameraMatricesData.set(viewMatrix, OFFSET_VIEW);
cameraMatricesData.set(cameraPos, OFFSET_CAMERA_POS);
// cameraMatricesData[OFFSET_EXPOSURE] = newExposureValue; // Update if exposure changes
// Bind the UBO and update its data on the GPU.
// Using gl.bufferSubData(target, offset, dataView) to update a portion or all of the buffer.
// Since we're updating the whole array from the start, offset is 0.
gl.bindBuffer(gl.UNIFORM_BUFFER, cameraUBO);
gl.bufferSubData(gl.UNIFORM_BUFFER, 0, cameraMatricesData); // Upload the updated data
gl.bindBuffer(gl.UNIFORM_BUFFER, null); // Unbind to avoid accidental modification
}
// Call updateCameraUBO() before drawing your scene elements each frame.
// For example, within your main render loop:
// requestAnimationFrame(function render(time) {
// updateCameraUBO();
// // ... draw your objects ...
// requestAnimationFrame(render);
// });
ಕೋಡ್ ಉದಾಹರಣೆ: ಒಂದು ಸರಳ ರೂಪಾಂತರ ಮ್ಯಾಟ್ರಿಕ್ಸ್ UBO
ಎಲ್ಲವನ್ನೂ ಒಟ್ಟಿಗೆ ಒಂದು ಹೆಚ್ಚು ಸಂಪೂರ್ಣ, ಆದರೂ ಸರಳೀಕೃತ ಉದಾಹರಣೆಗೆ ಸೇರಿಸೋಣ. ನಾವು ಒಂದು ತಿರುಗುವ ಘನವನ್ನು ರೆಂಡರ್ ಮಾಡುತ್ತಿದ್ದೇವೆ ಮತ್ತು ನಮ್ಮ ಕ್ಯಾಮರಾ ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳನ್ನು UBO ಬಳಸಿ ದಕ್ಷವಾಗಿ ನಿರ್ವಹಿಸಲು ಬಯಸುತ್ತೇವೆ ಎಂದು ಕಲ್ಪಿಸಿಕೊಳ್ಳಿ.
ವರ್ಟೆಕ್ಸ್ ಶೇಡರ್ (`cube.vert`)
#version 300 es
layout (location = 0) in vec4 a_position;
layout (location = 1) in vec3 a_normal;
uniform mat4 u_modelMatrix;
layout (std140) uniform CameraMatrices {
mat4 projection;
mat4 view;
vec3 cameraPosition;
float _padding;
} CameraData;
out vec3 v_normal;
out vec3 v_worldPosition;
void main() {
vec4 worldPosition = u_modelMatrix * a_position;
gl_Position = CameraData.projection * CameraData.view * worldPosition;
v_normal = mat3(u_modelMatrix) * a_normal;
v_worldPosition = worldPosition.xyz;
}
ಫ್ರಾಗ್ಮೆಂಟ್ ಶೇಡರ್ (`cube.frag`)
#version 300 es
precision highp float;
in vec3 v_normal;
in vec3 v_worldPosition;
uniform vec3 u_lightDirection;
uniform vec4 u_objectColor;
layout (std140) uniform CameraMatrices {
mat4 projection;
mat4 view;
vec3 cameraPosition;
float _padding;
} CameraData;
out vec4 outColor;
void main() {
// Basic diffuse lighting using a standard uniform for light direction
float diffuse = max(dot(normalize(v_normal), normalize(u_lightDirection)), 0.0);
// Simple specular lighting using camera position from UBO
vec3 lightDir = normalize(u_lightDirection);
vec3 norm = normalize(v_normal);
vec3 viewDir = normalize(CameraData.cameraPosition - v_worldPosition);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0);
vec4 ambientColor = u_objectColor * 0.1; // Simple ambient
vec4 diffuseColor = u_objectColor * diffuse;
vec4 specularColor = vec4(1.0, 1.0, 1.0, 1.0) * spec * 0.5;
outColor = ambientColor + diffuseColor + specularColor;
}
ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ (`main.js`) - ಪ್ರಮುಖ ತರ್ಕ
import { mat4, vec3 } from 'gl-matrix';
// Utility functions for shader compilation (simplified for brevity)
function createShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error('Shader compilation error:', gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
function createProgram(gl, vertexShaderSource, fragmentShaderSource) {
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
if (!vertexShader || !fragmentShader) return null;
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error('Shader program linking error:', gl.getProgramInfoLog(program));
gl.deleteProgram(program);
return null;
}
return program;
}
// Main application logic
async function main() {
const canvas = document.getElementById('gl-canvas');
const gl = canvas.getContext('webgl2');
if (!gl) {
console.error('WebGL2 not supported on this browser or device.');
return;
}
// Define shader sources inline for the example
const vertexShaderSource = `
#version 300 es
layout (location = 0) in vec4 a_position;
layout (location = 1) in vec3 a_normal;
uniform mat4 u_modelMatrix;
layout (std140) uniform CameraMatrices {
mat4 projection;
mat4 view;
vec3 cameraPosition;
float _padding;
} CameraData;
out vec3 v_normal;
out vec3 v_worldPosition;
void main() {
vec4 worldPosition = u_modelMatrix * a_position;
gl_Position = CameraData.projection * CameraData.view * worldPosition;
v_normal = mat3(u_modelMatrix) * a_normal;
v_worldPosition = worldPosition.xyz;
}
`;
const fragmentShaderSource = `
#version 300 es
precision highp float;
in vec3 v_normal;
in vec3 v_worldPosition;
uniform vec3 u_lightDirection;
uniform vec4 u_objectColor;
layout (std140) uniform CameraMatrices {
mat4 projection;
mat4 view;
vec3 cameraPosition;
float _padding;
} CameraData;
out vec4 outColor;
void main() {
float diffuse = max(dot(normalize(v_normal), normalize(u_lightDirection)), 0.0);
vec3 lightDir = normalize(u_lightDirection);
vec3 norm = normalize(v_normal);
vec3 viewDir = normalize(CameraData.cameraPosition - v_worldPosition);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0);
vec4 ambientColor = u_objectColor * 0.1;
vec4 diffuseColor = u_objectColor * diffuse;
vec4 specularColor = vec4(1.0, 1.0, 1.0, 1.0) * spec * 0.5;
outColor = ambientColor + diffuseColor + specularColor;
}
`;
const shaderProgram = createProgram(gl, vertexShaderSource, fragmentShaderSource);
if (!shaderProgram) return;
gl.useProgram(shaderProgram);
// --------------------------------------------------------------------
// Setup UBO for Camera Matrices
// --------------------------------------------------------------------
const UBO_BINDING_POINT = 0;
const cameraMatricesUBO = gl.createBuffer();
gl.bindBuffer(gl.UNIFORM_BUFFER, cameraMatricesUBO);
// UBO size: (2 * mat4) + (vec3 aligned to 16 bytes) + (float aligned to 16 bytes)
// = 64 + 64 + 16 + 16 = 160 bytes
const UBO_BYTE_SIZE = 160;
gl.bufferData(gl.UNIFORM_BUFFER, UBO_BYTE_SIZE, gl.DYNAMIC_DRAW); // Use DYNAMIC_DRAW for frequent updates
gl.bindBuffer(gl.UNIFORM_BUFFER, null);
// Get uniform block index and bind to the global binding point
const cameraBlockIndex = gl.getUniformBlockIndex(shaderProgram, 'CameraMatrices');
gl.uniformBlockBinding(shaderProgram, cameraBlockIndex, UBO_BINDING_POINT);
// CPU-side data storage for matrices and camera position
const projectionMatrix = mat4.create();
const viewMatrix = mat4.create();
const cameraPos = vec3.create(); // This will be updated dynamically
// Float32Array to hold all UBO data, carefully matching std140 layout
const cameraMatricesData = new Float32Array(UBO_BYTE_SIZE / Float32Array.BYTES_PER_ELEMENT); // 160 bytes / 4 bytes/float = 40 floats
// Offsets within the Float32Array (in units of floats)
const OFFSET_PROJECTION = 0;
const OFFSET_VIEW = 16;
const OFFSET_CAMERA_POS = 32;
const OFFSET_EXPOSURE = 36; // After 3 floats for vec3 + 1 float padding
// --------------------------------------------------------------------
// Setup Cube Geometry (simple, non-indexed cube for demonstration)
// --------------------------------------------------------------------
const cubePositions = new Float32Array([
// Front face
-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, // Triangle 1
-1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, // Triangle 2
// Back face
-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, // Triangle 1
-1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, // Triangle 2
// Top face
-1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, // Triangle 1
-1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, // Triangle 2
// Bottom face
-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, // Triangle 1
-1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, // Triangle 2
// Right face
1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, // Triangle 1
1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, // Triangle 2
// Left face
-1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, // Triangle 1
-1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0 // Triangle 2
]);
const cubeNormals = new Float32Array([
// Front
0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0,
// Back
0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0,
// Top
0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,
// Bottom
0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0,
// Right
1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,
// Left
-1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0
]);
const numVertices = cubePositions.length / 3;
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, cubePositions, gl.STATIC_DRAW);
const normalBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
gl.bufferData(gl.ARRAY_BUFFER, cubeNormals, gl.STATIC_DRAW);
gl.enableVertexAttribArray(0); // a_position
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(1); // a_normal
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
gl.vertexAttribPointer(1, 3, gl.FLOAT, false, 0, 0);
// --------------------------------------------------------------------
// Get locations for standard uniforms (u_modelMatrix, u_lightDirection, u_objectColor)
// --------------------------------------------------------------------
const uModelMatrixLoc = gl.getUniformLocation(shaderProgram, 'u_modelMatrix');
const uLightDirectionLoc = gl.getUniformLocation(shaderProgram, 'u_lightDirection');
const uObjectColorLoc = gl.getUniformLocation(shaderProgram, 'u_objectColor');
const modelMatrix = mat4.create();
const lightDirection = new Float32Array([0.5, 1.0, 0.0]);
const objectColor = new Float32Array([0.6, 0.8, 1.0, 1.0]);
// Set static uniforms once (if they don't change)
gl.uniform3fv(uLightDirectionLoc, lightDirection);
gl.uniform4fv(uObjectColorLoc, objectColor);
gl.enable(gl.DEPTH_TEST);
function updateAndDraw(currentTime) {
currentTime *= 0.001; // convert to seconds
// Resize canvas if needed (handles responsive layouts globally)
if (canvas.width !== canvas.clientWidth || canvas.height !== canvas.clientHeight) {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
gl.viewport(0, 0, canvas.width, canvas.height);
}
gl.clearColor(0.1, 0.1, 0.1, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// --- Update Camera UBO data ---
// Calculate camera matrices and position
mat4.perspective(projectionMatrix, Math.PI / 4, canvas.width / canvas.height, 0.1, 100.0);
const radius = 5;
const camX = Math.sin(currentTime * 0.5) * radius;
const camZ = Math.cos(currentTime * 0.5) * radius;
vec3.set(cameraPos, camX, 2, camZ);
mat4.lookAt(viewMatrix, cameraPos, vec3.fromValues(0, 0, 0), vec3.fromValues(0, 1, 0));
// Copy updated data into the CPU-side Float32Array
cameraMatricesData.set(projectionMatrix, OFFSET_PROJECTION);
cameraMatricesData.set(viewMatrix, OFFSET_VIEW);
cameraMatricesData.set(cameraPos, OFFSET_CAMERA_POS);
// cameraMatricesData[OFFSET_EXPOSURE] is 1.0 (set initially), not changed in loop for simplicity
// Bind UBO and update its data on GPU (one call for all camera matrices and position)
gl.bindBuffer(gl.UNIFORM_BUFFER, cameraMatricesUBO);
gl.bufferSubData(gl.UNIFORM_BUFFER, 0, cameraMatricesData);
gl.bindBuffer(gl.UNIFORM_BUFFER, null); // Unbind to avoid accidental modification
// --- Update and set model matrix (standard uniform) for the spinning cube ---
mat4.identity(modelMatrix);
mat4.translate(modelMatrix, modelMatrix, [0, 0, 0]);
mat4.rotateY(modelMatrix, modelMatrix, currentTime);
mat4.rotateX(modelMatrix, modelMatrix, currentTime * 0.7);
gl.uniformMatrix4fv(uModelMatrixLoc, false, modelMatrix);
// Draw the cube
gl.drawArrays(gl.TRIANGLES, 0, numVertices);
requestAnimationFrame(updateAndDraw);
}
requestAnimationFrame(updateAndDraw);
}
main();
ಈ ಸಮಗ್ರ ಉದಾಹರಣೆಯು ಪ್ರಮುಖ ಕಾರ್ಯಪ್ರವಾಹವನ್ನು ಪ್ರದರ್ಶಿಸುತ್ತದೆ: ಒಂದು UBO ಅನ್ನು ರಚಿಸಿ, ಅದಕ್ಕಾಗಿ ಜಾಗವನ್ನು ಹಂಚಿಕೆ ಮಾಡಿ (`std140` ಅನ್ನು ಗಮನದಲ್ಲಿಟ್ಟುಕೊಂಡು), ಮೌಲ್ಯಗಳು ಬದಲಾದಾಗ `bufferSubData` ನೊಂದಿಗೆ ಅದನ್ನು ನವೀಕರಿಸಿ, ಮತ್ತು ಅದನ್ನು ನಿಮ್ಮ ಶೇಡರ್ ಪ್ರೋಗ್ರಾಂ(ಗಳಿಗೆ) ಸ್ಥಿರವಾದ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ ಮೂಲಕ ಸಂಪರ್ಕಿಸಿ. ಪ್ರಮುಖ ಅಂಶವೆಂದರೆ ಎಲ್ಲಾ ಕ್ಯಾಮರಾ-ಸಂಬಂಧಿತ ಡೇಟಾ (ಪ್ರೊಜೆಕ್ಷನ್, ವ್ಯೂ, ಪೊಸಿಷನ್) ಈಗ ಪ್ರತಿ ಫ್ರೇಮ್ಗೆ ಅನೇಕ ವೈಯಕ್ತಿಕ gl.uniform... ಕರೆಗಳ ಬದಲು ಒಂದೇ gl.bufferSubData ಕರೆಯೊಂದಿಗೆ ನವೀಕರಿಸಲ್ಪಡುತ್ತವೆ. ಇದು ಎಪಿಐ ಓವರ್ಹೆಡ್ ಅನ್ನು ಗಮನಾರ್ಹವಾಗಿ ಕಡಿಮೆ ಮಾಡುತ್ತದೆ, ವಿಶೇಷವಾಗಿ ಈ ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳನ್ನು ಅನೇಕ ವಿಭಿನ್ನ ಶೇಡರ್ಗಳಲ್ಲಿ ಅಥವಾ ಅನೇಕ ರೆಂಡರಿಂಗ್ ಪಾಸ್ಗಳಿಗೆ ಬಳಸಿದ್ದರೆ ಸಂಭಾವ್ಯ ಕಾರ್ಯಕ್ಷಮತೆ ಲಾಭಗಳಿಗೆ ಕಾರಣವಾಗುತ್ತದೆ.
ಸುಧಾರಿತ UBO ತಂತ್ರಗಳು ಮತ್ತು ಉತ್ತಮ ಅಭ್ಯಾಸಗಳು
ನೀವು ಮೂಲಭೂತ ಅಂಶಗಳನ್ನು ಗ್ರಹಿಸಿದ ನಂತರ, UBOಗಳು ಹೆಚ್ಚು ಅತ್ಯಾಧುನಿಕ ರೆಂಡರಿಂಗ್ ಮಾದರಿಗಳು ಮತ್ತು ಆಪ್ಟಿಮೈಸೇಶನ್ಗಳಿಗೆ ದಾರಿ ತೆರೆಯುತ್ತವೆ.
ಕ್ರಿಯಾತ್ಮಕ ಡೇಟಾ ನವೀಕರಣಗಳು
ಆಗಾಗ್ಗೆ ಬದಲಾಗುವ ಡೇಟಾಗಾಗಿ (ಕ್ಯಾಮರಾ ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳು, ಬೆಳಕಿನ ಸ್ಥಾನಗಳು, ಅಥವಾ ಪ್ರತಿ ಫ್ರೇಮ್ನಲ್ಲಿ ನವೀಕರಿಸುವ ಅನಿಮೇಟೆಡ್ ಗುಣಲಕ್ಷಣಗಳಂತಹ), ನೀವು ಪ್ರಾಥಮಿಕವಾಗಿ gl.bufferSubData ಅನ್ನು ಬಳಸುತ್ತೀರಿ. ನೀವು ಆರಂಭದಲ್ಲಿ gl.bufferData ನೊಂದಿಗೆ ಬಫರ್ ಅನ್ನು ಹಂಚಿಕೆ ಮಾಡಿದಾಗ, ಈ ಬಫರ್ನ ವಿಷಯವನ್ನು ಆಗಾಗ್ಗೆ ನವೀಕರಿಸಲಾಗುವುದು ಎಂದು ಜಿಪಿಯುಗೆ ತಿಳಿಸಲು gl.DYNAMIC_DRAW ಅಥವಾ gl.STREAM_DRAW ನಂತಹ ಬಳಕೆಯ ಸುಳಿವನ್ನು ಆಯ್ಕೆಮಾಡಿ. ನಿಯಮಿತವಾಗಿ ಬದಲಾಗುವ ಡೇಟಾಗೆ gl.DYNAMIC_DRAW ಸಾಮಾನ್ಯ ಡೀಫಾಲ್ಟ್ ಆಗಿದ್ದರೂ, ನವೀಕರಣಗಳು ತುಂಬಾ ಆಗಾಗ್ಗೆ ಇದ್ದರೆ ಮತ್ತು ಡೇಟಾವನ್ನು ಸಂಪೂರ್ಣವಾಗಿ ಬದಲಾಯಿಸುವ ಮೊದಲು ಒಮ್ಮೆ ಅಥವಾ ಕೆಲವು ಬಾರಿ ಮಾತ್ರ ಬಳಸಿದರೆ gl.STREAM_DRAW ಅನ್ನು ಪರಿಗಣಿಸಿ, ಏಕೆಂದರೆ ಇದು ಈ ಬಳಕೆಯ ಪ್ರಕರಣಕ್ಕಾಗಿ ಆಪ್ಟಿಮೈಜ್ ಮಾಡಲು ಡ್ರೈವರ್ಗೆ ಸುಳಿವು ನೀಡಬಹುದು.
ನವೀಕರಿಸುವಾಗ, gl.bufferSubData(target, offset, dataView, srcOffset, length) ನಿಮ್ಮ ಪ್ರಾಥಮಿಕ ಸಾಧನವಾಗಿದೆ. offset ಪ್ಯಾರಾಮೀಟರ್ UBO ನಲ್ಲಿ ಎಲ್ಲಿ (ಬೈಟ್ಗಳಲ್ಲಿ) dataView (ನಿಮ್ಮ Float32Array ಅಥವಾ ಅಂತಹುದೇ) ಬರೆಯಲು ಪ್ರಾರಂಭಿಸಬೇಕು ಎಂಬುದನ್ನು ನಿರ್ದಿಷ್ಟಪಡಿಸುತ್ತದೆ. ನಿಮ್ಮ UBO ನ ಒಂದು ಭಾಗವನ್ನು ಮಾತ್ರ ನೀವು ನವೀಕರಿಸುತ್ತಿದ್ದರೆ ಇದು ನಿರ್ಣಾಯಕವಾಗಿದೆ. ಉದಾಹರಣೆಗೆ, ನೀವು UBO ನಲ್ಲಿ ಅನೇಕ ದೀಪಗಳನ್ನು ಹೊಂದಿದ್ದರೆ ಮತ್ತು ಕೇವಲ ಒಂದು ದೀಪದ ಗುಣಲಕ್ಷಣಗಳು ಬದಲಾದರೆ, ನೀವು ಸಂಪೂರ್ಣ ಬಫರ್ ಅನ್ನು ಮತ್ತೆ ಅಪ್ಲೋಡ್ ಮಾಡದೆ, ಅದರ ಬೈಟ್ ಆಫ್ಸೆಟ್ ಅನ್ನು ಲೆಕ್ಕಾಚಾರ ಮಾಡುವ ಮೂಲಕ ಆ ದೀಪದ ಡೇಟಾವನ್ನು ಮಾತ್ರ ನವೀಕರಿಸಬಹುದು. ಈ ಸೂಕ್ಷ್ಮ-ಧಾನ್ಯದ ನಿಯಂತ್ರಣವು ಒಂದು ಶಕ್ತಿಯುತ ಆಪ್ಟಿಮೈಸೇಶನ್ ಆಗಿದೆ.
ಆಗಾಗ್ಗೆ ನವೀಕರಣಗಳಿಗಾಗಿ ಕಾರ್ಯಕ್ಷಮತೆಯ ಪರಿಗಣನೆಗಳು
UBOಗಳೊಂದಿಗೆ ಸಹ, ಆಗಾಗ್ಗೆ ನವೀಕರಣಗಳು ಇನ್ನೂ ಸಿಪಿಯು ಡೇಟಾವನ್ನು ಜಿಪಿಯು ಮೆಮೊರಿಗೆ ಕಳುಹಿಸುವುದನ್ನು ಒಳಗೊಂಡಿರುತ್ತವೆ, ಇದು ಸೀಮಿತ ಸಂಪನ್ಮೂಲವಾಗಿದೆ ಮತ್ತು ಓವರ್ಹೆಡ್ ಅನ್ನು ಉಂಟುಮಾಡುವ ಕಾರ್ಯಾಚರಣೆಯಾಗಿದೆ. ಆಗಾಗ್ಗೆ UBO ನವೀಕರಣಗಳನ್ನು ಆಪ್ಟಿಮೈಜ್ ಮಾಡಲು:
- ಬದಲಾದದ್ದನ್ನು ಮಾತ್ರ ನವೀಕರಿಸಿ: ಇದು ಮೂಲಭೂತವಾಗಿದೆ. ನಿಮ್ಮ UBO ನ ಡೇಟಾದ ಒಂದು ಸಣ್ಣ ಭಾಗ ಮಾತ್ರ ಬದಲಾಗಿದ್ದರೆ, ಕೇವಲ ಮಾರ್ಪಡಿಸಿದ ಭಾಗವನ್ನು ಕಳುಹಿಸಲು ನಿಖರವಾದ ಬೈಟ್ ಆಫ್ಸೆಟ್ ಮತ್ತು ಸಣ್ಣ ಡೇಟಾ ವ್ಯೂ (ಉದಾ., ನಿಮ್ಮ
Float32Arrayನ ಒಂದು ಸ್ಲೈಸ್) ನೊಂದಿಗೆgl.bufferSubDataಬಳಸಿ. ಅಗತ್ಯವಿಲ್ಲದಿದ್ದರೆ ಸಂಪೂರ್ಣ ಬಫರ್ ಅನ್ನು ಮರುಕಳುಹಿಸುವುದನ್ನು ತಪ್ಪಿಸಿ. - ಡಬಲ್-ಬಫರಿಂಗ್ ಅಥವಾ ರಿಂಗ್ ಬಫರ್ಗಳು: ಅತ್ಯಂತ ಹೆಚ್ಚಿನ-ಆವರ್ತನ ನವೀಕರಣಗಳಿಗಾಗಿ, ಉದಾಹರಣೆಗೆ ನೂರಾರು ವಸ್ತುಗಳನ್ನು ಅನಿಮೇಟ್ ಮಾಡುವುದು ಅಥವಾ ಪ್ರತಿ ಫ್ರೇಮ್ನ ಡೇಟಾ ವಿಭಿನ್ನವಾಗಿರುವ ಸಂಕೀರ್ಣ ಕಣ ವ್ಯವಸ್ಥೆಗಳು, ಅನೇಕ UBOಗಳನ್ನು ಹಂಚಿಕೆ ಮಾಡುವುದನ್ನು ಪರಿಗಣಿಸಿ. ನೀವು ಈ UBOಗಳ ಮೂಲಕ ಸೈಕಲ್ ಮಾಡಬಹುದು (ಒಂದು ರಿಂಗ್ ಬಫರ್ ವಿಧಾನ), ಜಿಪಿಯು ಇನ್ನೂ ಇನ್ನೊಂದರಿಂದ ಓದುತ್ತಿರುವಾಗ ಸಿಪಿಯು ಒಂದು ಬಫರ್ಗೆ ಬರೆಯಲು ಅನುವು ಮಾಡಿಕೊಡುತ್ತದೆ. ಇದು ಸಿಪಿಯು ಬರೆಯಲು ಪ್ರಯತ್ನಿಸುತ್ತಿರುವ ಬಫರ್ನಿಂದ ಜಿಪಿಯು ಓದುವುದನ್ನು ಮುಗಿಸಲು ಸಿಪಿಯು ಕಾಯುವುದನ್ನು ತಡೆಯಬಹುದು, ಪೈಪ್ಲೈನ್ ಸ್ಥಗಿತಗಳನ್ನು ತಗ್ಗಿಸಬಹುದು ಮತ್ತು ಸಿಪಿಯು-ಜಿಪಿಯು ಸಮಾನಾಂತರತೆಯನ್ನು ಸುಧಾರಿಸಬಹುದು. ಇದು ಹೆಚ್ಚು ಸುಧಾರಿತ ತಂತ್ರವಾಗಿದೆ ಆದರೆ ಹೆಚ್ಚು ಕ್ರಿಯಾತ್ಮಕ ದೃಶ್ಯಗಳಲ್ಲಿ ಗಮನಾರ್ಹ ಲಾಭಗಳನ್ನು ನೀಡಬಹುದು.
- ಡೇಟಾ ಪ್ಯಾಕಿಂಗ್: ಯಾವಾಗಲೂ, ಅನಗತ್ಯ ಮೆಮೊರಿ ಹಂಚಿಕೆಗಳು ಮತ್ತು ಪ್ರತಿಗಳನ್ನು ತಪ್ಪಿಸಲು ನಿಮ್ಮ ಸಿಪಿಯು-ಬದಿಯ ಡೇಟಾ ಅರೇಯನ್ನು ಬಿಗಿಯಾಗಿ ಪ್ಯಾಕ್ ಮಾಡಲಾಗಿದೆಯೆ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ (
std140ನಿಯಮಗಳನ್ನು ಗೌರವಿಸುತ್ತಿರುವಾಗ). ಸಣ್ಣ ಡೇಟಾ ಎಂದರೆ ಕಡಿಮೆ ವರ್ಗಾವಣೆ ಸಮಯ.
ಬಹು ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ಗಳು
ನೀವು ಪ್ರತಿ ಶೇಡರ್ ಪ್ರೋಗ್ರಾಂಗೆ ಅಥವಾ ಪ್ರತಿ ಅಪ್ಲಿಕೇಶನ್ಗೆ ಒಂದೇ ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ಗೆ ಸೀಮಿತವಾಗಿಲ್ಲ. ಒಂದು ಸಂಕೀರ್ಣ 3D ದೃಶ್ಯ ಅಥವಾ ಎಂಜಿನ್ ಬಹುತೇಕ ಖಂಡಿತವಾಗಿಯೂ ಬಹು, ತಾರ್ಕಿಕವಾಗಿ ಬೇರ್ಪಡಿಸಲಾದ UBOಗಳಿಂದ ಪ್ರಯೋಜನ ಪಡೆಯುತ್ತದೆ:
CameraMatricesUBO: ಪ್ರೊಜೆಕ್ಷನ್, ವ್ಯೂ, ಇನ್ವರ್ಸ್ ವ್ಯೂ, ಮತ್ತು ಕ್ಯಾಮರಾ ವರ್ಲ್ಡ್ ಪೊಸಿಷನ್ಗಾಗಿ. ಇದು ದೃಶ್ಯಕ್ಕೆ ಜಾಗತಿಕವಾಗಿದೆ ಮತ್ತು ಕ್ಯಾಮರಾ ಚಲಿಸಿದಾಗ ಮಾತ್ರ ಬದಲಾಗುತ್ತದೆ.LightInfoUBO: ಸಕ್ರಿಯ ದೀಪಗಳ ಅರೇ, ಅವುಗಳ ಸ್ಥಾನಗಳು, ದಿಕ್ಕುಗಳು, ಬಣ್ಣಗಳು, ಪ್ರಕಾರಗಳು, ಮತ್ತು ಅಟೆನ್ಯುಯೇಷನ್ ಪ್ಯಾರಾಮೀಟರ್ಗಳಿಗಾಗಿ. ದೀಪಗಳನ್ನು ಸೇರಿಸಿದಾಗ, ತೆಗೆದುಹಾಕಿದಾಗ, ಅಥವಾ ಅನಿಮೇಟ್ ಮಾಡಿದಾಗ ಇದು ಬದಲಾಗಬಹುದು.MaterialPropertiesUBO: ಹೊಳಪು, ಪ್ರತಿಫಲನ, PBR ಪ್ಯಾರಾಮೀಟರ್ಗಳು (ಒರಟುತನ, ಲೋಹೀಯತೆ), ಇತ್ಯಾದಿಗಳಂತಹ ಸಾಮಾನ್ಯ ವಸ್ತು ಪ್ಯಾರಾಮೀಟರ್ಗಳಿಗಾಗಿ, ಇವು ವಸ್ತುಗಳ ಗುಂಪುಗಳಿಂದ ಹಂಚಿಕೊಳ್ಳಲ್ಪಡಬಹುದು ಅಥವಾ ಪ್ರತಿ-ವಸ್ತುವಿಗೆ ಸೂಚ್ಯಂಕಿತವಾಗಬಹುದು.SceneGlobalsUBO: ಜಾಗತಿಕ ಸಮಯ, ಮಂಜು ಪ್ಯಾರಾಮೀಟರ್ಗಳು, ಪರಿಸರ ನಕ್ಷೆ ತೀವ್ರತೆ, ಜಾಗತಿಕ ಆಂಬಿಯೆಂಟ್ ಬಣ್ಣ, ಇತ್ಯಾದಿಗಳಿಗಾಗಿ.AnimationDataUBO: ಅಸ್ಥಿಪಂಜರ ಅನಿಮೇಷನ್ ಡೇಟಾಗಾಗಿ (ಜಾಯಿಂಟ್ ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳು) ಇದನ್ನು ಒಂದೇ ರಿಗ್ ಬಳಸುವ ಅನೇಕ ಅನಿಮೇಟೆಡ್ ಪಾತ್ರಗಳಿಂದ ಹಂಚಿಕೊಳ್ಳಬಹುದು.
ಪ್ರತಿಯೊಂದು ವಿಭಿನ್ನ ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ ತನ್ನದೇ ಆದ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ ಮತ್ತು ತನ್ನದೇ ಆದ ಸಂಬಂಧಿತ UBO ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ. ಈ ಮಾಡ್ಯುಲರ್ ವಿಧಾನವು ನಿಮ್ಮ ಶೇಡರ್ ಕೋಡ್ ಅನ್ನು ಸ್ವಚ್ಛಗೊಳಿಸುತ್ತದೆ, ನಿಮ್ಮ ಡೇಟಾ ನಿರ್ವಹಣೆಯನ್ನು ಹೆಚ್ಚು ಸಂಘಟಿತವಾಗಿಸುತ್ತದೆ, ಮತ್ತು ಜಿಪಿಯುನಲ್ಲಿ ಉತ್ತಮ ಕ್ಯಾಶಿಂಗ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ. ಶೇಡರ್ನಲ್ಲಿ ಇದು ಹೀಗೆ ಕಾಣಿಸಬಹುದು:
#version 300 es
// ... attributes ...
layout (std140) uniform CameraMatrices { /* ... camera uniforms ... */ } CameraData;
layout (std140) uniform LightInfo {
vec3 positions[MAX_LIGHTS];
vec4 colors[MAX_LIGHTS];
// ... other light properties ...
} SceneLights;
layout (std140) uniform Material {
vec4 albedoColor;
float metallic;
float roughness;
// ... other material properties ...
} ObjectMaterial;
// ... other uniforms and outputs ...
ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ನಲ್ಲಿ, ನೀವು ನಂತರ ಪ್ರತಿ ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ಗೆ ಬ್ಲಾಕ್ ಸೂಚ್ಯಂಕವನ್ನು ಪಡೆಯುತ್ತೀರಿ (ಉದಾ., 'LightInfo', 'Material') ಮತ್ತು ಅವುಗಳನ್ನು ವಿಭಿನ್ನ, ವಿಶಿಷ್ಟ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ಗಳಿಗೆ (ಉದಾ., 1, 2) ಬಂಧಿಸುತ್ತೀರಿ:
// For LightInfo UBO
const LIGHT_UBO_BINDING_POINT = 1;
const lightInfoUBO = gl.createBuffer();
gl.bindBuffer(gl.UNIFORM_BUFFER, lightInfoUBO);
gl.bufferData(gl.UNIFORM_BUFFER, LIGHT_UBO_BYTE_SIZE, gl.DYNAMIC_DRAW); // Size calculated based on lights array
gl.bindBuffer(gl.UNIFORM_BUFFER, null);
const lightBlockIndex = gl.getUniformBlockIndex(shaderProgram, 'LightInfo');
gl.uniformBlockBinding(shaderProgram, lightBlockIndex, LIGHT_UBO_BINDING_POINT);
// For Material UBO
const MATERIAL_UBO_BINDING_POINT = 2;
const materialUBO = gl.createBuffer();
gl.bindBuffer(gl.UNIFORM_BUFFER, materialUBO);
gl.bufferData(gl.UNIFORM_BUFFER, MATERIAL_UBO_BYTE_SIZE, gl.STATIC_DRAW); // Material might be static per object
gl.bindBuffer(gl.UNIFORM_BUFFER, null);
const materialBlockIndex = gl.getUniformBlockIndex(shaderProgram, 'Material');
gl.uniformBlockBinding(shaderProgram, materialBlockIndex, MATERIAL_UBO_BINDING_POINT);
// ... then update lightInfoUBO and materialUBO with gl.bufferSubData as needed ...
ಪ್ರೋಗ್ರಾಂಗಳಾದ್ಯಂತ UBOಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳುವುದು
UBOಗಳ ಅತ್ಯಂತ ಶಕ್ತಿಯುತ ಮತ್ತು ದಕ್ಷತೆ-ವರ್ಧಿಸುವ ವೈಶಿಷ್ಟ್ಯಗಳಲ್ಲಿ ಒಂದೆಂದರೆ ಅವುಗಳನ್ನು ಸಲೀಸಾಗಿ ಹಂಚಿಕೊಳ್ಳುವ ಸಾಮರ್ಥ್ಯ. ನೀವು ಅಪಾರದರ್ಶಕ ವಸ್ತುಗಳಿಗೆ ಒಂದು ಶೇಡರ್, ಪಾರದರ್ಶಕ ವಸ್ತುಗಳಿಗೆ ಇನ್ನೊಂದು, ಮತ್ತು ಪೋಸ್ಟ್-ಪ್ರೊಸೆಸಿಂಗ್ ಪರಿಣಾಮಗಳಿಗೆ ಮೂರನೆಯದನ್ನು ಹೊಂದಿದ್ದೀರಿ ಎಂದು ಕಲ್ಪಿಸಿಕೊಳ್ಳಿ. ಮೂರಕ್ಕೂ ಒಂದೇ ಕ್ಯಾಮರಾ ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳು ಬೇಕಾಗಬಹುದು. UBOಗಳೊಂದಿಗೆ, ನೀವು *ಒಂದು* cameraMatricesUBO ಅನ್ನು ರಚಿಸುತ್ತೀರಿ, ಅದರ ಡೇಟಾವನ್ನು ಪ್ರತಿ ಫ್ರೇಮ್ಗೆ ಒಮ್ಮೆ ನವೀಕರಿಸುತ್ತೀರಿ (gl.bufferSubData ಬಳಸಿ), ಮತ್ತು ನಂತರ ಅದನ್ನು *ಎಲ್ಲಾ* ಸಂಬಂಧಿತ ಶೇಡರ್ ಪ್ರೋಗ್ರಾಂಗಳಿಗೆ ಒಂದೇ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ಗೆ (ಉದಾ., 0) ಬಂಧಿಸುತ್ತೀರಿ. ಪ್ರತಿ ಪ್ರೋಗ್ರಾಂ ತನ್ನ CameraMatrices ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ ಅನ್ನು ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ 0 ಗೆ ಲಿಂಕ್ ಮಾಡಿರುತ್ತದೆ.
ಇದು ಸಿಪಿಯು-ಜಿಪಿಯು ಬಸ್ನಾದ್ಯಂತ ಪುನರಾವರ್ತಿತ ಡೇಟಾ ವರ್ಗಾವಣೆಗಳನ್ನು ತೀವ್ರವಾಗಿ ಕಡಿಮೆ ಮಾಡುತ್ತದೆ ಮತ್ತು ಎಲ್ಲಾ ಶೇಡರ್ಗಳು ಒಂದೇ ರೀತಿಯ ಅಪ್-ಟು-ಡೇಟ್ ಕ್ಯಾಮರಾ ಮಾಹಿತಿಯೊಂದಿಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತಿವೆ ಎಂದು ಖಚಿತಪಡಿಸುತ್ತದೆ. ಇದು ದೃಶ್ಯ ಸ್ಥಿರತೆಗೆ ನಿರ್ಣಾಯಕವಾಗಿದೆ, ವಿಶೇಷವಾಗಿ ಬಹು ರೆಂಡರ್ ಪಾಸ್ಗಳು ಅಥವಾ ವಿಭಿನ್ನ ವಸ್ತು ಪ್ರಕಾರಗಳನ್ನು ಹೊಂದಿರುವ ಸಂಕೀರ್ಣ ದೃಶ್ಯಗಳಲ್ಲಿ.
// Assume shaderProgramOpaque, shaderProgramTransparent, shaderProgramPostProcess are linked
const UBO_BINDING_POINT_CAMERA = 0; // The chosen binding point for camera data
// Bind the camera UBO to this binding point for the opaque shader
const opaqueCameraBlockIndex = gl.getUniformBlockIndex(shaderProgramOpaque, 'CameraMatrices');
gl.uniformBlockBinding(shaderProgramOpaque, opaqueCameraBlockIndex, UBO_BINDING_POINT_CAMERA);
// Bind the same camera UBO to the same binding point for the transparent shader
const transparentCameraBlockIndex = gl.getUniformBlockIndex(shaderProgramTransparent, 'CameraMatrices');
gl.uniformBlockBinding(shaderProgramTransparent, transparentCameraBlockIndex, UBO_BINDING_POINT_CAMERA);
// And for the post-processing shader
const postProcessCameraBlockIndex = gl.getUniformBlockIndex(shaderProgramPostProcess, 'CameraMatrices');
gl.uniformBlockBinding(shaderProgramPostProcess, postProcessCameraBlockIndex, UBO_BINDING_POINT_CAMERA);
// The cameraMatricesUBO is then updated once per frame, and all three shaders automatically access the latest data.
ಇನ್ಸ್ಟನ್ಸ್ಡ್ ರೆಂಡರಿಂಗ್ಗಾಗಿ UBOಗಳು
UBOಗಳು ಪ್ರಾಥಮಿಕವಾಗಿ ಯೂನಿಫಾರ್ಮ್ ಡೇಟಾಗಾಗಿ ವಿನ್ಯಾಸಗೊಳಿಸಲಾಗಿದ್ದರೂ, ಅವು ಇನ್ಸ್ಟನ್ಸ್ಡ್ ರೆಂಡರಿಂಗ್ನಲ್ಲಿ, ವಿಶೇಷವಾಗಿ WebGL2 ನ gl.drawArraysInstanced ಅಥವಾ gl.drawElementsInstanced ನೊಂದಿಗೆ ಸಂಯೋಜಿಸಿದಾಗ, ಶಕ್ತಿಯುತ ಪೋಷಕ ಪಾತ್ರವನ್ನು ವಹಿಸುತ್ತವೆ. ಅತ್ಯಂತ ದೊಡ್ಡ ಸಂಖ್ಯೆಯ ಇನ್ಸ್ಟನ್ಸ್ಗಳಿಗೆ, ಪ್ರತಿ-ಇನ್ಸ್ಟನ್ಸ್ ಡೇಟಾವನ್ನು ಸಾಮಾನ್ಯವಾಗಿ gl.vertexAttribDivisor ನೊಂದಿಗೆ ಆಟ್ರಿಬ್ಯೂಟ್ ಬಫರ್ ಆಬ್ಜೆಕ್ಟ್ (ABO) ಮೂಲಕ ಉತ್ತಮವಾಗಿ ನಿರ್ವಹಿಸಲಾಗುತ್ತದೆ.
ಆದಾಗ್ಯೂ, UBOಗಳು ಶೇಡರ್ನಲ್ಲಿ ಸೂಚ್ಯಂಕದಿಂದ ಪ್ರವೇಶಿಸಲ್ಪಡುವ ಡೇಟಾದ ಅರೇಗಳನ್ನು ಪರಿಣಾಮಕಾರಿಯಾಗಿ ಸಂಗ್ರಹಿಸಬಹುದು, ಇನ್ಸ್ಟನ್ಸ್ ಗುಣಲಕ್ಷಣಗಳಿಗಾಗಿ ಲುಕಪ್ ಟೇಬಲ್ಗಳಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತವೆ, ವಿಶೇಷವಾಗಿ ಇನ್ಸ್ಟನ್ಸ್ಗಳ ಸಂಖ್ಯೆಯು UBO ಗಾತ್ರದ ಮಿತಿಗಳಲ್ಲಿದ್ದರೆ. ಉದಾಹರಣೆಗೆ, ಸಣ್ಣದಿಂದ ಮಧ್ಯಮ ಸಂಖ್ಯೆಯ ಇನ್ಸ್ಟನ್ಸ್ಗಳ ಮಾಡೆಲ್ ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳಿಗಾಗಿ mat4 ನ ಅರೇಯನ್ನು UBO ನಲ್ಲಿ ಸಂಗ್ರಹಿಸಬಹುದು. ಪ್ರತಿ ಇನ್ಸ್ಟನ್ಸ್ ನಂತರ ಅಂತರ್ನಿರ್ಮಿತ gl_InstanceID ಶೇಡರ್ ವೇರಿಯಬಲ್ ಅನ್ನು UBO ಒಳಗೆ ಅರೇಯಿಂದ ತನ್ನ ನಿರ್ದಿಷ್ಟ ಮ್ಯಾಟ್ರಿಕ್ಸ್ ಅನ್ನು ಪ್ರವೇಶಿಸಲು ಬಳಸುತ್ತದೆ. ಈ ಮಾದರಿಯು ಇನ್ಸ್ಟನ್ಸ್-ನಿರ್ದಿಷ್ಟ ಡೇಟಾಗೆ ABOಗಳಿಗಿಂತ ಕಡಿಮೆ ಸಾಮಾನ್ಯವಾಗಿದೆ ಆದರೆ ಕೆಲವು ಸನ್ನಿವೇಶಗಳಿಗೆ, ಇನ್ಸ್ಟನ್ಸ್ ಡೇಟಾ ಹೆಚ್ಚು ಸಂಕೀರ್ಣವಾಗಿದ್ದಾಗ (ಉದಾ., ಪ್ರತಿ ಇನ್ಸ್ಟನ್ಸ್ಗೆ ಪೂರ್ಣ ರಚನೆ) ಅಥವಾ ಇನ್ಸ್ಟನ್ಸ್ಗಳ ಸಂಖ್ಯೆಯನ್ನು UBO ಗಾತ್ರದ ಮಿತಿಗಳಲ್ಲಿ ನಿರ್ವಹಿಸಬಹುದಾದಾಗ, ಕಾರ್ಯಸಾಧ್ಯ ಪರ್ಯಾಯವಾಗಿದೆ.
#version 300 es
// ... other attributes and uniforms ...
layout (std140) uniform InstanceData {
mat4 instanceModelMatrices[MAX_INSTANCES]; // Array of model matrices
vec4 instanceColors[MAX_INSTANCES]; // Array of colors
} InstanceTransforms;
void main() {
// Access instance-specific data using gl_InstanceID
mat4 modelMatrix = InstanceTransforms.instanceModelMatrices[gl_InstanceID];
vec4 instanceColor = InstanceTransforms.instanceColors[gl_InstanceID];
gl_Position = CameraData.projection * CameraData.view * modelMatrix * a_position;
// ... apply instanceColor to final output ...
}
`MAX_INSTANCES` ಶೇಡರ್ನಲ್ಲಿ ಕಂಪೈಲ್-ಟೈಮ್ ಸ್ಥಿರಾಂಕ (`const int` ಅಥವಾ ಪ್ರಿಪ್ರೊಸೆಸರ್ ಡಿಫೈನ್) ಆಗಿರಬೇಕು ಮತ್ತು ಒಟ್ಟಾರೆ UBO ಗಾತ್ರವು `gl.MAX_UNIFORM_BLOCK_SIZE` ನಿಂದ ಸೀಮಿತವಾಗಿದೆ ಎಂಬುದನ್ನು ನೆನಪಿಡಿ (ಇದನ್ನು ರನ್ಟೈಮ್ನಲ್ಲಿ ಪ್ರಶ್ನಿಸಬಹುದು, ಸಾಮಾನ್ಯವಾಗಿ ಆಧುನಿಕ ಹಾರ್ಡ್ವೇರ್ನಲ್ಲಿ 16KB-64KB ವ್ಯಾಪ್ತಿಯಲ್ಲಿರುತ್ತದೆ).
UBOಗಳನ್ನು ಡೀಬಗ್ ಮಾಡುವುದು
ಡೇಟಾ ಪ್ಯಾಕಿಂಗ್ನ ಅಂತರ್ಗತ ಸ್ವರೂಪ ಮತ್ತು ಡೇಟಾವು ಜಿಪಿಯುನಲ್ಲಿ ಇರುವುದರಿಂದ UBOಗಳನ್ನು ಡೀಬಗ್ ಮಾಡುವುದು ಟ್ರಿಕಿ ಆಗಿರಬಹುದು. ನಿಮ್ಮ ರೆಂಡರಿಂಗ್ ತಪ್ಪಾಗಿ ಕಂಡರೆ, ಅಥವಾ ಡೇಟಾ ಭ್ರಷ್ಟಗೊಂಡಂತೆ ತೋರಿದರೆ, ಈ ಡೀಬಗ್ ಮಾಡುವ ಹಂತಗಳನ್ನು ಪರಿಗಣಿಸಿ:
- `std140` ಲೇಔಟ್ ಅನ್ನು ನಿಖರವಾಗಿ ಪರಿಶೀಲಿಸಿ: ಇದು ದೋಷಗಳ ಅತ್ಯಂತ ಸಾಮಾನ್ಯ ಮೂಲವಾಗಿದೆ. ನಿಮ್ಮ ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ `Float32Array` ಆಫ್ಸೆಟ್ಗಳು, ಗಾತ್ರಗಳು, ಮತ್ತು ಪ್ಯಾಡಿಂಗ್ ಅನ್ನು *ಪ್ರತಿ* ಸದಸ್ಯನಿಗೆ `std140` ನಿಯಮಗಳ ವಿರುದ್ಧ ಎರಡು ಬಾರಿ ಪರಿಶೀಲಿಸಿ. ನಿಮ್ಮ ಮೆಮೊರಿ ಲೇಔಟ್ನ ರೇಖಾಚಿತ್ರಗಳನ್ನು ಬರೆಯಿರಿ, ಬೈಟ್ಗಳನ್ನು ಸ್ಪಷ್ಟವಾಗಿ ಗುರುತಿಸಿ. ಒಂದೇ ಒಂದು ಬೈಟ್ ತಪ್ಪಾದ ಜೋಡಣೆಯು ನಂತರದ ಡೇಟಾವನ್ನು ಭ್ರಷ್ಟಗೊಳಿಸಬಹುದು.
- `gl.getUniformBlockIndex` ಪರಿಶೀಲಿಸಿ: ನೀವು ರವಾನಿಸುವ ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ ಹೆಸರು (ಉದಾ., `'CameraMatrices'`) ನಿಮ್ಮ ಶೇಡರ್ ಮತ್ತು ನಿಮ್ಮ ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ ಕೋಡ್ ನಡುವೆ *ನಿಖರವಾಗಿ* (ಕೇಸ್-ಸೆನ್ಸಿಟಿವ್) ಹೊಂದಿಕೆಯಾಗುತ್ತದೆ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.
- `gl.uniformBlockBinding` ಪರಿಶೀಲಿಸಿ: ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ನಲ್ಲಿ ನಿರ್ದಿಷ್ಟಪಡಿಸಿದ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ (ಉದಾ., `0`) ಶೇಡರ್ ಬ್ಲಾಕ್ ಬಳಸಲು ನೀವು ಉದ್ದೇಶಿಸಿರುವ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ಗೆ ಹೊಂದಿಕೆಯಾಗುತ್ತದೆ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.
- `gl.bufferSubData`/`gl.bufferData` ಬಳಕೆಯನ್ನು ಖಚಿತಪಡಿಸಿ: *ಇತ್ತೀಚಿನ* ಸಿಪಿಯು-ಬದಿಯ ಡೇಟಾವನ್ನು ಜಿಪಿಯು ಬಫರ್ಗೆ ವರ್ಗಾಯಿಸಲು ನೀವು ನಿಜವಾಗಿಯೂ `gl.bufferSubData` (ಅಥವಾ `gl.bufferData`) ಅನ್ನು ಕರೆಯುತ್ತಿದ್ದೀರಿ ಎಂದು ಪರಿಶೀಲಿಸಿ. ಇದನ್ನು ಮರೆತರೆ ಜಿಪಿಯುನಲ್ಲಿ ಹಳೆಯ ಡೇಟಾ ಉಳಿಯುತ್ತದೆ.
- WebGL ಇನ್ಸ್ಪೆಕ್ಟರ್ ಪರಿಕರಗಳನ್ನು ಬಳಸಿ: ಬ್ರೌಸರ್ ಡೆವಲಪರ್ ಪರಿಕರಗಳು (Spector.js, ಅಥವಾ ಬ್ರೌಸರ್ ಅಂತರ್ನಿರ್ಮಿತ WebGL ಡೀಬಗ್ಗರ್ಗಳಂತಹ) ಅಮೂಲ್ಯವಾಗಿವೆ. ಅವುಗಳು ಆಗಾಗ್ಗೆ ನಿಮ್ಮ UBOಗಳ ವಿಷಯಗಳನ್ನು ನೇರವಾಗಿ ಜಿಪಿಯುನಲ್ಲಿ ತೋರಿಸಬಹುದು, ಡೇಟಾವನ್ನು ಸರಿಯಾಗಿ ಅಪ್ಲೋಡ್ ಮಾಡಲಾಗಿದೆಯೇ ಮತ್ತು ಶೇಡರ್ ನಿಜವಾಗಿ ಏನು ಓದುತ್ತಿದೆ ಎಂಬುದನ್ನು ಪರಿಶೀಲಿಸಲು ಸಹಾಯ ಮಾಡುತ್ತದೆ. ಅವು ಎಪಿಐ ದೋಷಗಳು ಅಥವಾ ಎಚ್ಚರಿಕೆಗಳನ್ನು ಸಹ ಹೈಲೈಟ್ ಮಾಡಬಹುದು.
- ಡೇಟಾವನ್ನು ಹಿಂತಿರುಗಿ ಓದಿ (ಡೀಬಗ್ ಮಾಡಲು ಮಾತ್ರ): ಅಭಿವೃದ್ಧಿಯಲ್ಲಿ, ಅದರ ವಿಷಯಗಳನ್ನು ಪರಿಶೀಲಿಸಲು ನೀವು `gl.getBufferSubData(target, srcByteOffset, dstBuffer, dstOffset, length)` ಬಳಸಿ UBO ಡೇಟಾವನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ಸಿಪಿಯುಗೆ ಹಿಂತಿರುಗಿ ಓದಬಹುದು. ಈ ಕಾರ್ಯಾಚರಣೆಯು ತುಂಬಾ ನಿಧಾನವಾಗಿದೆ ಮತ್ತು ಪೈಪ್ಲೈನ್ ಸ್ಥಗಿತವನ್ನು ಪರಿಚಯಿಸುತ್ತದೆ, ಆದ್ದರಿಂದ ಇದನ್ನು * ಎಂದಿಗೂ* ಉತ್ಪಾದನಾ ಕೋಡ್ನಲ್ಲಿ ಮಾಡಬಾರದು.
- ಸರಳೀಕರಿಸಿ ಮತ್ತು ಪ್ರತ್ಯೇಕಿಸಿ: ಒಂದು ಸಂಕೀರ್ಣ UBO ಕಾರ್ಯನಿರ್ವಹಿಸದಿದ್ದರೆ, ಅದನ್ನು ಸರಳಗೊಳಿಸಿ. ಒಂದೇ `float` ಅಥವಾ `vec4` ಅನ್ನು ಹೊಂದಿರುವ UBO ನೊಂದಿಗೆ ಪ್ರಾರಂಭಿಸಿ, ಅದನ್ನು ಕಾರ್ಯನಿರ್ವಹಿಸುವಂತೆ ಮಾಡಿ, ಮತ್ತು ಕ್ರಮೇಣ ಸಂಕೀರ್ಣತೆಯನ್ನು ಸೇರಿಸಿ (`vec3`, ಅರೇಗಳು, ರಚನೆಗಳು) ಒಂದು ಸಮಯದಲ್ಲಿ ಒಂದು ಹೆಜ್ಜೆ, ಪ್ರತಿ ಸೇರ್ಪಡೆಯನ್ನು ಪರಿಶೀಲಿಸುತ್ತಾ.
ಕಾರ್ಯಕ್ಷಮತೆಯ ಪರಿಗಣನೆಗಳು ಮತ್ತು ಆಪ್ಟಿಮೈಸೇಶನ್ ತಂತ್ರಗಳು
UBOಗಳು ಗಮನಾರ್ಹ ಕಾರ್ಯಕ್ಷಮತೆ ಪ್ರಯೋಜನಗಳನ್ನು ನೀಡುತ್ತವೆಯಾದರೂ, ಅವುಗಳ ಅತ್ಯುತ್ತಮ ಬಳಕೆಗೆ ಎಚ್ಚರಿಕೆಯ ಪರಿಗಣನೆ ಮತ್ತು ಆಧಾರವಾಗಿರುವ ಹಾರ್ಡ್ವೇರ್ ಪರಿಣಾಮಗಳ ತಿಳುವಳಿಕೆ ಅಗತ್ಯ.
ಮೆಮೊರಿ ನಿರ್ವಹಣೆ ಮತ್ತು ಡೇಟಾ ಲೇಔಟ್
- `std140` ಅನ್ನು ಮನಸ್ಸಿನಲ್ಲಿಟ್ಟುಕೊಂಡು ಬಿಗಿಯಾದ ಪ್ಯಾಕಿಂಗ್: `std140` ನಿಯಮಗಳನ್ನು ಕಟ್ಟುನಿಟ್ಟಾಗಿ ಪಾಲಿಸುತ್ತಾ, ನಿಮ್ಮ ಸಿಪಿಯು-ಬದಿಯ ಡೇಟಾವನ್ನು ಸಾಧ್ಯವಾದಷ್ಟು ಬಿಗಿಯಾಗಿ ಪ್ಯಾಕ್ ಮಾಡಲು ಯಾವಾಗಲೂ ಗುರಿಯಿರಿಸಿ. ಇದು ವರ್ಗಾಯಿಸಲಾದ ಮತ್ತು ಸಂಗ್ರಹಿಸಲಾದ ಡೇಟಾದ ಪ್ರಮಾಣವನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ. ಸಿಪಿಯು ಬದಿಯಲ್ಲಿ ಅನಗತ್ಯ ಪ್ಯಾಡಿಂಗ್ ಮೆಮೊರಿ ಮತ್ತು ಬ್ಯಾಂಡ್ವಿಡ್ತ್ ಅನ್ನು ವ್ಯರ್ಥ ಮಾಡುತ್ತದೆ. `std140` ಆಫ್ಸೆಟ್ಗಳನ್ನು ಲೆಕ್ಕಾಚಾರ ಮಾಡುವ ಪರಿಕರಗಳು ಇಲ್ಲಿ ಜೀವ ಉಳಿಸಬಹುದು.
- ಪುನರಾವರ್ತಿತ ಡೇಟಾವನ್ನು ತಪ್ಪಿಸಿ: ನಿಮ್ಮ ಅಪ್ಲಿಕೇಶನ್ ಮತ್ತು ಎಲ್ಲಾ ಶೇಡರ್ಗಳ ಸಂಪೂರ್ಣ ಜೀವಿತಾವಧಿಯಲ್ಲಿ ಡೇಟಾ ನಿಜವಾಗಿಯೂ ಸ್ಥಿರವಾಗಿದ್ದರೆ ಅದನ್ನು UBO ನಲ್ಲಿ ಹಾಕಬೇಡಿ; ಅಂತಹ ಸಂದರ್ಭಗಳಲ್ಲಿ, ಒಮ್ಮೆ ಹೊಂದಿಸಲಾದ ಸರಳ ಸ್ಟ್ಯಾಂಡರ್ಡ್ ಯೂನಿಫಾರ್ಮ್ ಸಾಕು. ಅಂತೆಯೇ, ಡೇಟಾ ಕಟ್ಟುನಿಟ್ಟಾಗಿ ಪ್ರತಿ-ವರ್ಟೆಕ್ಸ್ ಆಗಿದ್ದರೆ, ಅದು ಯೂನಿಫಾರ್ಮ್ ಅಲ್ಲ, ಒಂದು ಗುಣಲಕ್ಷಣವಾಗಿರಬೇಕು.
- ಸರಿಯಾದ ಬಳಕೆಯ ಸುಳಿವುಗಳೊಂದಿಗೆ ಹಂಚಿಕೆ ಮಾಡಿ: ಅಪರೂಪವಾಗಿ ಅಥವಾ ಎಂದಿಗೂ ಬದಲಾಗದ UBOಗಳಿಗೆ `gl.STATIC_DRAW` ಬಳಸಿ (ಉದಾ., ಸ್ಥಿರ ದೃಶ್ಯ ಪ್ಯಾರಾಮೀಟರ್ಗಳು). ಆಗಾಗ್ಗೆ ಬದಲಾಗುವವುಗಳಿಗೆ `gl.DYNAMIC_DRAW` ಬಳಸಿ (ಉದಾ., ಕ್ಯಾಮರಾ ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳು, ಅನಿಮೇಟೆಡ್ ಬೆಳಕಿನ ಸ್ಥಾನಗಳು). ಮತ್ತು ಬಹುತೇಕ ಪ್ರತಿ ಫ್ರೇಮ್ನಲ್ಲಿ ಬದಲಾಗುವ ಮತ್ತು ಒಮ್ಮೆ ಮಾತ್ರ ಬಳಸಲಾಗುವ ಡೇಟಾಗೆ `gl.STREAM_DRAW` ಅನ್ನು ಪರಿಗಣಿಸಿ (ಉದಾ., ಪ್ರತಿ ಫ್ರೇಮ್ನಲ್ಲಿ ಸಂಪೂರ್ಣವಾಗಿ ಮರು-ರಚಿಸಲಾದ ಕೆಲವು ಕಣ ವ್ಯವಸ್ಥೆಯ ಡೇಟಾ). ಈ ಸುಳಿವುಗಳು ಜಿಪಿಯು ಡ್ರೈವರ್ಗೆ ಮೆಮೊರಿ ಹಂಚಿಕೆ ಮತ್ತು ಕ್ಯಾಶಿಂಗ್ ಅನ್ನು ಹೇಗೆ ಉತ್ತಮವಾಗಿ ಆಪ್ಟಿಮೈಜ್ ಮಾಡುವುದು ಎಂಬುದರ ಕುರಿತು ಮಾರ್ಗದರ್ಶನ ನೀಡುತ್ತವೆ.
UBOಗಳೊಂದಿಗೆ ಡ್ರಾ ಕರೆಗಳನ್ನು ಬ್ಯಾಚಿಂಗ್ ಮಾಡುವುದು
ಒಂದೇ ಶೇಡರ್ ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ಹಂಚಿಕೊಳ್ಳುವ ಆದರೆ ವಿಭಿನ್ನ ಯೂನಿಫಾರ್ಮ್ ಗುಣಲಕ್ಷಣಗಳನ್ನು ಹೊಂದಿರುವ ಅನೇಕ ವಸ್ತುಗಳನ್ನು ರೆಂಡರ್ ಮಾಡಬೇಕಾದಾಗ UBOಗಳು ವಿಶೇಷವಾಗಿ ಪ್ರಕಾಶಿಸುತ್ತವೆ (ಉದಾ., ವಿಭಿನ್ನ ಮಾಡೆಲ್ ಮ್ಯಾಟ್ರಿಕ್ಸ್ಗಳು, ಬಣ್ಣಗಳು, ಅಥವಾ ವಸ್ತು ಐಡಿಗಳು). ವೈಯಕ್ತಿಕ ಯೂನಿಫಾರ್ಮ್ಗಳನ್ನು ನವೀಕರಿಸುವ ಮತ್ತು ಪ್ರತಿ ವಸ್ತುವಿಗೆ ಹೊಸ ಡ್ರಾ ಕರೆಯನ್ನು ನೀಡುವ ದುಬಾರಿ ಕಾರ್ಯಾಚರಣೆಯ ಬದಲು, ಬ್ಯಾಚಿಂಗ್ ಅನ್ನು ಹೆಚ್ಚಿಸಲು ನೀವು UBOಗಳನ್ನು ಬಳಸಿಕೊಳ್ಳಬಹುದು:
- ಒಂದೇ ರೀತಿಯ ವಸ್ತುಗಳನ್ನು ಗುಂಪು ಮಾಡಿ: ಒಂದೇ ಶೇಡರ್ ಪ್ರೋಗ್ರಾಂ ಮತ್ತು UBOಗಳನ್ನು ಹಂಚಿಕೊಳ್ಳಬಹುದಾದ ವಸ್ತುಗಳನ್ನು ಗುಂಪು ಮಾಡಲು ನಿಮ್ಮ ದೃಶ್ಯ ಗ್ರಾಫ್ ಅನ್ನು ಸಂಘಟಿಸಿ (ಉದಾ., ಒಂದೇ ಲೈಟಿಂಗ್ ಮಾದರಿಯನ್ನು ಬಳಸುವ ಎಲ್ಲಾ ಅಪಾರದರ್ಶಕ ವಸ್ತುಗಳು).
- ಪ್ರತಿ-ವಸ್ತುವಿನ ಡೇಟಾವನ್ನು ಸಂಗ್ರಹಿಸಿ: ಅಂತಹ ಗುಂಪಿನೊಳಗಿನ ವಸ್ತುಗಳಿಗೆ, ಅವುಗಳ ವಿಶಿಷ್ಟ ಯೂನಿಫಾರ್ಮ್ ಡೇಟಾವನ್ನು (ಅವುಗಳ ಮಾಡೆಲ್ ಮ್ಯಾಟ್ರಿಕ್ಸ್, ಅಥವಾ ವಸ್ತು ಸೂಚ್ಯಂಕದಂತಹ) ದಕ್ಷವಾಗಿ ಸಂಗ್ರಹಿಸಬಹುದು. ಅತ್ಯಂತ ಅನೇಕ ಇನ್ಸ್ಟನ್ಸ್ಗಳಿಗೆ, ಇದು ಸಾಮಾನ್ಯವಾಗಿ ಪ್ರತಿ-ಇನ್ಸ್ಟನ್ಸ್ ಡೇಟಾವನ್ನು ಆಟ್ರಿಬ್ಯೂಟ್ ಬಫರ್ ಆಬ್ಜೆಕ್ಟ್ (ABO) ನಲ್ಲಿ ಸಂಗ್ರಹಿಸುವುದು ಮತ್ತು ಇನ್ಸ್ಟನ್ಸ್ಡ್ ರೆಂಡರಿಂಗ್ ಅನ್ನು ಬಳಸುವುದು ಎಂದರ್ಥ (`gl.drawArraysInstanced` ಅಥವಾ `gl.drawElementsInstanced`). ಶೇಡರ್ ನಂತರ `gl_InstanceID` ಅನ್ನು ABO ನಿಂದ ಸರಿಯಾದ ಮಾಡೆಲ್ ಮ್ಯಾಟ್ರಿಕ್ಸ್ ಅಥವಾ ಇತರ ಗುಣಲಕ್ಷಣಗಳನ್ನು ಹುಡುಕಲು ಬಳಸುತ್ತದೆ.
- UBOಗಳು ಲುಕಪ್ ಟೇಬಲ್ಗಳಾಗಿ (ಕಡಿಮೆ ಇನ್ಸ್ಟನ್ಸ್ಗಳಿಗಾಗಿ): ಹೆಚ್ಚು ಸೀಮಿತ ಸಂಖ್ಯೆಯ ಇನ್ಸ್ಟನ್ಸ್ಗಳಿಗಾಗಿ, UBOಗಳು ವಾಸ್ತವವಾಗಿ ರಚನೆಗಳ ಅರೇಗಳನ್ನು ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಬಹುದು, ಅಲ್ಲಿ ಪ್ರತಿ ರಚನೆಯು ಒಂದು ವಸ್ತುವಿನ ಗುಣಲಕ್ಷಣಗಳನ್ನು ಹೊಂದಿರುತ್ತದೆ. ಶೇಡರ್ ಇನ್ನೂ `gl_InstanceID` ಅನ್ನು ತನ್ನ ನಿರ್ದಿಷ್ಟ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಲು ಬಳಸುತ್ತದೆ (ಉದಾ., `InstanceData.modelMatrices[gl_InstanceID]`). ಇದು ಅನ್ವಯವಾಗಿದ್ದರೆ ಗುಣಲಕ್ಷಣ ವಿಭಾಜಕಗಳ ಸಂಕೀರ್ಣತೆಯನ್ನು ತಪ್ಪಿಸುತ್ತದೆ.
ಈ ವಿಧಾನವು ಒಂದೇ ಡ್ರಾ ಕರೆಯೊಂದಿಗೆ ಅನೇಕ ಇನ್ಸ್ಟನ್ಸ್ಗಳನ್ನು ಸಮಾನಾಂತರವಾಗಿ ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಜಿಪಿಯುಗೆ ಅನುವು ಮಾಡಿಕೊಡುವ ಮೂಲಕ ಎಪಿಐ ಕರೆ ಓವರ್ಹೆಡ್ ಅನ್ನು ಗಮನಾರ್ಹವಾಗಿ ಕಡಿಮೆ ಮಾಡುತ್ತದೆ, ವಿಶೇಷವಾಗಿ ಹೆಚ್ಚಿನ ವಸ್ತು ಎಣಿಕೆಗಳನ್ನು ಹೊಂದಿರುವ ದೃಶ್ಯಗಳಲ್ಲಿ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ನಾಟಕೀಯವಾಗಿ ಹೆಚ್ಚಿಸುತ್ತದೆ.
ಆಗಾಗ್ಗೆ ಬಫರ್ ನವೀಕರಣಗಳನ್ನು ತಪ್ಪಿಸುವುದು
ಒಂದೇ `gl.bufferSubData` ಕರೆ, ಅನೇಕ ವೈಯಕ್ತಿಕ ಯೂನಿಫಾರ್ಮ್ ಕರೆಗಳಿಗಿಂತ ಹೆಚ್ಚು ದಕ್ಷವಾಗಿದ್ದರೂ, ಉಚಿತವಲ್ಲ. ಇದು ಮೆಮೊರಿ ವರ್ಗಾವಣೆಯನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ ಮತ್ತು ಸಿಂಕ್ರೊನೈಸೇಶನ್ ಪಾಯಿಂಟ್ಗಳನ್ನು ಪರಿಚಯಿಸಬಹುದು. ಅಪರೂಪವಾಗಿ ಅಥವಾ ಊಹಿಸಬಹುದಾದಂತೆ ಬದಲಾಗುವ ಡೇಟಾಗಾಗಿ:
- ನವೀಕರಣಗಳನ್ನು ಕನಿಷ್ಠಗೊಳಿಸಿ: ಅದರ ಆಧಾರವಾಗಿರುವ ಡೇಟಾ ನಿಜವಾಗಿಯೂ ಬದಲಾದಾಗ ಮಾತ್ರ UBO ಅನ್ನು ನವೀಕರಿಸಿ. ನಿಮ್ಮ ಕ್ಯಾಮರಾ ಸ್ಥಿರವಾಗಿದ್ದರೆ, ಅದರ UBO ಅನ್ನು ಒಮ್ಮೆ ನವೀಕರಿಸಿ. ಬೆಳಕಿನ ಮೂಲವು ಚಲಿಸುತ್ತಿಲ್ಲವಾದರೆ, ಅದರ ಬಣ್ಣ ಅಥವಾ ತೀವ್ರತೆ ಬದಲಾದಾಗ ಮಾತ್ರ ಅದರ UBO ಅನ್ನು ನವೀಕರಿಸಿ.
- ಸಬ್-ಡೇಟಾ vs. ಪೂರ್ಣ-ಡೇಟಾ: ದೊಡ್ಡ UBO ನ ಒಂದು ಸಣ್ಣ ಭಾಗ ಮಾತ್ರ ಬದಲಾದರೆ (ಉದಾ., ಹತ್ತು ದೀಪಗಳ ಅರೇಯಲ್ಲಿ ಒಂದು ದೀಪ), ಸಂಪೂರ್ಣ UBO ಅನ್ನು ಮರು-ಅಪ್ಲೋಡ್ ಮಾಡುವ ಬದಲು, ಕೇವಲ ಬದಲಾದ ಭಾಗವನ್ನು ಆವರಿಸುವ ನಿಖರವಾದ ಬೈಟ್ ಆಫ್ಸೆಟ್ ಮತ್ತು ಸಣ್ಣ ಡೇಟಾ ವ್ಯೂ ನೊಂದಿಗೆ `gl.bufferSubData` ಬಳಸಿ. ಇದು ವರ್ಗಾಯಿಸಲಾದ ಡೇಟಾದ ಪ್ರಮಾಣವನ್ನು ಕನಿಷ್ಠಗೊಳಿಸುತ್ತದೆ.
- ಬದಲಾಗದ ಡೇಟಾ: ಎಂದಿಗೂ ಬದಲಾಗದ ನಿಜವಾದ ಸ್ಥಿರ ಯೂನಿಫಾರ್ಮ್ಗಳಿಗಾಗಿ, ಅವುಗಳನ್ನು ಒಮ್ಮೆ `gl.bufferData(..., gl.STATIC_DRAW)` ನೊಂದಿಗೆ ಹೊಂದಿಸಿ, ಮತ್ತು ನಂತರ ಆ UBO ನಲ್ಲಿ ಯಾವುದೇ ನವೀಕರಣ ಫಂಕ್ಷನ್ಗಳನ್ನು ಮತ್ತೆ ಕರೆಯಬೇಡಿ. ಇದು ಜಿಪಿಯು ಡ್ರೈವರ್ಗೆ ಡೇಟಾವನ್ನು ಸೂಕ್ತ, ಓದಲು-ಮಾತ್ರ ಮೆಮೊರಿಯಲ್ಲಿ ಇರಿಸಲು ಅನುವು ಮಾಡಿಕೊಡುತ್ತದೆ.
ಬೆಂಚ್ಮಾರ್ಕಿಂಗ್ ಮತ್ತು ಪ್ರೊಫೈಲಿಂಗ್
ಯಾವುದೇ ಆಪ್ಟಿಮೈಸೇಶನ್ನಂತೆಯೇ, ನಿಮ್ಮ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಯಾವಾಗಲೂ ಪ್ರೊಫೈಲ್ ಮಾಡಿ. ಅಡಚಣೆಗಳು ಎಲ್ಲಿವೆ ಎಂದು ಊಹಿಸಬೇಡಿ; ಅವುಗಳನ್ನು ಅಳೆಯಿರಿ. ಬ್ರೌಸರ್ ಕಾರ್ಯಕ್ಷಮತೆ ಮಾನಿಟರ್ಗಳು (ಉದಾ., Chrome DevTools, Firefox Developer Tools), Spector.js, ಅಥವಾ ಇತರ WebGL ಡೀಬಗ್ಗರ್ಗಳಂತಹ ಪರಿಕರಗಳು ಅಡಚಣೆಗಳನ್ನು ಗುರುತಿಸಲು ಸಹಾಯ ಮಾಡಬಹುದು. ಸಿಪಿಯು-ಜಿಪಿಯು ವರ್ಗಾವಣೆಗಳು, ಡ್ರಾ ಕರೆಗಳು, ಶೇಡರ್ ಕಾರ್ಯಗತಗೊಳಿಸುವಿಕೆ, ಮತ್ತು ಒಟ್ಟಾರೆ ಫ್ರೇಮ್ ಸಮಯದ ಮೇಲೆ ಖರ್ಚು ಮಾಡಿದ ಸಮಯವನ್ನು ಅಳೆಯಿರಿ. ದೀರ್ಘ ಫ್ರೇಮ್ಗಳು, WebGL ಕರೆಗಳಿಗೆ ಸಂಬಂಧಿಸಿದ ಸಿಪಿಯು ಬಳಕೆಯಲ್ಲಿನ ಸ್ಪೈಕ್ಗಳು, ಅಥವಾ ಅತಿಯಾದ ಜಿಪಿಯು ಮೆಮೊರಿ ಬಳಕೆಗಾಗಿ ನೋಡಿ. ಈ ಪ್ರಾಯೋಗಿಕ ಡೇಟಾವು ನಿಮ್ಮ UBO ಆಪ್ಟಿಮೈಸೇಶನ್ ಪ್ರಯತ್ನಗಳಿಗೆ ಮಾರ್ಗದರ್ಶನ ನೀಡುತ್ತದೆ, ನೀವು ಗ್ರಹಿಸಿದ ಅಡಚಣೆಗಳಿಗಿಂತ ಹೆಚ್ಚಾಗಿ ನಿಜವಾದ ಅಡಚಣೆಗಳನ್ನು ಪರಿಹರಿಸುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸುತ್ತದೆ. ಜಾಗತಿಕ ಕಾರ್ಯಕ್ಷಮತೆಯ ಪರಿಗಣನೆಗಳು ಎಂದರೆ ವಿವಿಧ ಸಾಧನಗಳು ಮತ್ತು ನೆಟ್ವರ್ಕ್ ಪರಿಸ್ಥಿತಿಗಳಲ್ಲಿ ಪ್ರೊಫೈಲಿಂಗ್ ಮಾಡುವುದು ನಿರ್ಣಾಯಕವಾಗಿದೆ.
ಸಾಮಾನ್ಯ ಅಪಾಯಗಳು ಮತ್ತು ಅವುಗಳನ್ನು ತಪ್ಪಿಸುವುದು ಹೇಗೆ
ಅನುಭವಿ ಡೆವಲಪರ್ಗಳು ಸಹ UBOಗಳೊಂದಿಗೆ ಕೆಲಸ ಮಾಡುವಾಗ ಬಲೆಗೆ ಬೀಳಬಹುದು. ಇಲ್ಲಿ ಕೆಲವು ಸಾಮಾನ್ಯ ಸಮಸ್ಯೆಗಳು ಮತ್ತು ಅವುಗಳನ್ನು ತಪ್ಪಿಸುವ ತಂತ್ರಗಳು:
ಹೊಂದಿಕೆಯಾಗದ ಡೇಟಾ ಲೇಔಟ್ಗಳು
ಇದು ಅತ್ಯಂತ ಆಗಾಗ್ಗೆ ಮತ್ತು ನಿರಾಶಾದಾಯಕ ಸಮಸ್ಯೆಯಾಗಿದೆ. ನಿಮ್ಮ ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ `Float32Array` (ಅಥವಾ ಇತರ ಟೈಪ್ ಮಾಡಿದ ಅರೇ) ನಿಮ್ಮ GLSL ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ನ `std140` ನಿಯಮಗಳೊಂದಿಗೆ ಸಂಪೂರ್ಣವಾಗಿ ಹೊಂದಿಕೆಯಾಗದಿದ್ದರೆ, ನಿಮ್ಮ ಶೇಡರ್ಗಳು ಕಸವನ್ನು ಓದುತ್ತವೆ. ಇದು ತಪ್ಪಾದ ರೂಪಾಂತರಗಳು, ವಿಲಕ್ಷಣ ಬಣ್ಣಗಳು, ಅಥವಾ ಕ್ರ್ಯಾಶ್ಗಳಾಗಿ ಪ್ರಕಟವಾಗಬಹುದು.
- ಸಾಮಾನ್ಯ ದೋಷಗಳ ಉದಾಹರಣೆಗಳು:
- ತಪ್ಪಾದ `vec3` ಪ್ಯಾಡಿಂಗ್: `vec3`ಗಳು `std140` ನಲ್ಲಿ 16 ಬೈಟ್ಗಳಿಗೆ ಜೋಡಿಸಲ್ಪಟ್ಟಿವೆ ಎಂಬುದನ್ನು ಮರೆಯುವುದು, ಅವು ಕೇವಲ 12 ಬೈಟ್ಗಳನ್ನು ಆಕ್ರಮಿಸಿಕೊಂಡರೂ ಸಹ.
- ಅರೇ ಅಂಶ ಅಲೈನ್ಮೆಂಟ್: UBO ಒಳಗೆ ಅರೇಯ ಪ್ರತಿಯೊಂದು ಅಂಶವು (ಏಕ ಫ್ಲೋಟ್ಗಳು ಅಥವಾ ಇಂಟ್ಗಳು ಸಹ) 16-ಬೈಟ್ ಗಡಿಗೆ ಜೋಡಿಸಲ್ಪಟ್ಟಿದೆ ಎಂಬುದನ್ನು ಅರಿತುಕೊಳ್ಳದಿರುವುದು.
- ರಚನೆ ಅಲೈನ್ಮೆಂಟ್: ರಚನೆಯ ಸದಸ್ಯರ ನಡುವೆ ಅಗತ್ಯವಿರುವ ಪ್ಯಾಡಿಂಗ್ ಅಥವಾ ರಚನೆಯ ಒಟ್ಟು ಗಾತ್ರವನ್ನು ತಪ್ಪಾಗಿ ಲೆಕ್ಕಾಚಾರ ಮಾಡುವುದು, ಅದು ಕೂಡ 16 ಬೈಟ್ಗಳ ಗುಣಕವಾಗಿರಬೇಕು.
ತಪ್ಪಿಸುವುದು: ಯಾವಾಗಲೂ ದೃಶ್ಯ ಮೆಮೊರಿ ಲೇಔಟ್ ರೇಖಾಚಿತ್ರವನ್ನು ಅಥವಾ ನಿಮಗಾಗಿ `std140` ಆಫ್ಸೆಟ್ಗಳನ್ನು ಲೆಕ್ಕಾಚಾರ ಮಾಡುವ ಸಹಾಯಕ ಲೈಬ್ರರಿಯನ್ನು ಬಳಸಿ. ಡೀಬಗ್ ಮಾಡಲು ಆಫ್ಸೆಟ್ಗಳನ್ನು ಎಚ್ಚರಿಕೆಯಿಂದ ಹಸ್ತಚಾಲಿತವಾಗಿ ಲೆಕ್ಕಾಚಾರ ಮಾಡಿ, ಬೈಟ್ ಆಫ್ಸೆಟ್ಗಳು ಮತ್ತು ಪ್ರತಿ ಅಂಶದ ಅಗತ್ಯವಿರುವ ಅಲೈನ್ಮೆಂಟ್ ಅನ್ನು ಗಮನಿಸಿ. ಅತ್ಯಂತ ನಿಖರವಾಗಿರಿ.
ತಪ್ಪಾದ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ಗಳು
ನೀವು ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ನಲ್ಲಿ `gl.bindBufferBase` ಅಥವಾ `gl.bindBufferRange` ನೊಂದಿಗೆ ಹೊಂದಿಸಿದ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್, `gl.uniformBlockBinding` ಬಳಸಿ ಯೂನಿಫಾರ್ಮ್ ಬ್ಲಾಕ್ಗೆ ನೀವು ಸ್ಪಷ್ಟವಾಗಿ (ಅಥವಾ ಸೂಚ್ಯವಾಗಿ, ಶೇಡರ್ನಲ್ಲಿ ನಿರ್ದಿಷ್ಟಪಡಿಸದಿದ್ದರೆ) ನಿಯೋಜಿಸಿದ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ಗೆ ಹೊಂದಿಕೆಯಾಗದಿದ್ದರೆ, ನಿಮ್ಮ ಶೇಡರ್ ಡೇಟಾವನ್ನು ಕಂಡುಹಿಡಿಯುವುದಿಲ್ಲ.
ತಪ್ಪಿಸುವುದು: ಸ್ಥಿರವಾದ ಹೆಸರಿಸುವ ಸಂಪ್ರದಾಯವನ್ನು ವ್ಯಾಖ್ಯಾನಿಸಿ ಅಥವಾ ನಿಮ್ಮ ಬೈಂಡಿಂಗ್ ಪಾಯಿಂಟ್ಗಳಿಗಾಗಿ ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ ಸ್ಥಿರಾಂಕಗಳನ್ನು ಬಳಸಿ. ಈ ಮೌಲ್ಯಗಳನ್ನು ನಿಮ್ಮ ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ ಕೋಡ್ನಾದ್ಯಂತ ಮತ್ತು ನಿಮ್ಮ ಶೇಡರ್ ಘೋಷಣೆಗಳೊಂದಿಗೆ ಪರಿಕಲ್ಪನಾತ್ಮಕವಾಗಿ ಸ್ಥಿರವಾಗಿ ಪರಿಶೀಲಿಸಿ. ಡೀಬಗ್ ಮಾಡುವ ಪರಿಕರಗಳು ಆಗಾಗ್ಗೆ ಸಕ್ರಿಯ ಯೂನಿಫಾರ್ಮ್ ಬಫರ್ ಬೈಂಡಿಂಗ್ಗಳನ್ನು ಪರಿಶೀಲಿಸಬಹುದು.
ಬಫರ್ ಡೇಟಾವನ್ನು ನವೀಕರಿಸಲು ಮರೆಯುವುದು
ನಿಮ್ಮ ಸಿಪಿಯು-ಬದಿಯ ಯೂನಿಫಾರ್ಮ್ ಮೌಲ್ಯಗಳು ಬದಲಾದರೆ (ಉದಾ., ಮ್ಯಾಟ್ರಿಕ್ಸ್ ಅನ್ನು ನವೀಕರಿಸಲಾಗಿದೆ) ಆದರೆ ಹೊಸ ಮೌಲ್ಯಗಳನ್ನು ಜಿಪಿಯು ಬಫರ್ಗೆ ವರ್ಗಾಯಿಸಲು `gl.bufferSubData` (ಅಥವಾ `gl.bufferData`) ಅನ್ನು ಕರೆಯಲು ನೀವು ಮರೆತರೆ, ನಿಮ್ಮ ಶೇಡರ್ಗಳು ಹಿಂದಿನ ಫ್ರೇಮ್ನಿಂದ ಅಥವಾ ಆರಂಭಿಕ ಅಪ್ಲೋಡ್ನಿಂದ ಹಳೆಯ ಡೇಟಾವನ್ನು ಬಳಸುವುದನ್ನು ಮುಂದುವರಿಸುತ್ತವೆ.
ತಪ್ಪಿಸುವುದು: ನಿಮ್ಮ UBO ನವೀಕರಣಗಳನ್ನು ಸ್ಪಷ್ಟ ಫಂಕ್ಷನ್ನಲ್ಲಿ (ಉದಾ., `updateCameraUBO()`) ಸುತ್ತುವರಿಯಿರಿ, ಅದನ್ನು ನಿಮ್ಮ ರೆಂಡರ್ ಲೂಪ್ನಲ್ಲಿ ಸೂಕ್ತ ಸಮಯದಲ್ಲಿ ಕರೆಯಲಾಗುತ್ತದೆ (ಉದಾ., ಪ್ರತಿ ಫ್ರೇಮ್ಗೆ ಒಮ್ಮೆ, ಅಥವಾ ಕ್ಯಾಮರಾ ಚಲನೆಯಂತಹ ನಿರ್ದಿಷ್ಟ ಈವೆಂಟ್ನಲ್ಲಿ). ಈ ಫಂಕ್ಷನ್ ಸ್ಪಷ್ಟವಾಗಿ UBO ಅನ್ನು ಬಂಧಿಸುತ್ತದೆ ಮತ್ತು ಸರಿಯಾದ ಬಫರ್ ಡೇಟಾ ನವೀಕರಣ ವಿಧಾನವನ್ನು ಕರೆಯುತ್ತದೆ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.
WebGL ಕಾಂಟೆಕ್ಸ್ಟ್ ನಷ್ಟ ನಿರ್ವಹಣೆ
ಎಲ್ಲಾ WebGL ಸಂಪನ್ಮೂಲಗಳಂತೆ (ಟೆಕ್ಸ್ಚರ್ಗಳು, ಬಫರ್ಗಳು, ಶೇಡರ್ ಪ್ರೋಗ್ರಾಂಗಳು), WebGL ಕಾಂಟೆಕ್ಸ್ಟ್ ಕಳೆದುಹೋದರೆ UBOಗಳನ್ನು ಮರುಸೃಷ್ಟಿಸಬೇಕು (ಉದಾ., ಬ್ರೌಸರ್ ಟ್ಯಾಬ್ ಕ್ರ್ಯಾಶ್, ಜಿಪಿಯು ಡ್ರೈವರ್ ಮರುಹೊಂದಿಸುವಿಕೆ, ಅಥವಾ ಸಂಪನ್ಮೂಲ ಬಳಲಿಕೆಯಿಂದ). ನಿಮ್ಮ ಅಪ್ಲಿಕೇಶನ್ `webglcontextlost` ಮತ್ತು `webglcontextrestored` ಈವೆಂಟ್ಗಳನ್ನು ಆಲಿಸುವ ಮೂಲಕ ಮತ್ತು UBOಗಳು, ಅವುಗಳ ಡೇಟಾ, ಮತ್ತು ಅವುಗಳ ಬೈಂಡಿಂಗ್ಗಳು ಸೇರಿದಂತೆ ಎಲ್ಲಾ ಜಿಪಿಯು-ಬದಿಯ ಸಂಪನ್ಮೂಲಗಳನ್ನು ಮರು-ಪ್ರಾರಂಭಿಸುವ ಮೂಲಕ ಇದನ್ನು ನಿರ್ವಹಿಸಲು ಸಾಕಷ್ಟು ದೃಢವಾಗಿರಬೇಕು.
ತಪ್ಪಿಸುವುದು: ಎಲ್ಲಾ WebGL ಆಬ್ಜೆಕ್ಟ್ಗಳಿಗೆ ಸರಿಯಾದ ಕಾಂಟೆಕ್ಸ್ಟ್ ನಷ್ಟ ಮತ್ತು ಪುನಃಸ್ಥಾಪನೆ ತರ್ಕವನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಿ. ಇದು ಜಾಗತಿಕ ನಿಯೋಜನೆಗಾಗಿ ವಿಶ್ವಾಸಾರ್ಹ WebGL ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ನಿರ್ಮಿಸುವ ನಿರ್ಣಾಯಕ ಅಂಶವಾಗಿದೆ.
WebGL ಡೇಟಾ ವರ್ಗಾವಣೆಯ ಭವಿಷ್ಯ: UBOಗಳ ಆಚೆಗೆ
UBOಗಳು WebGL2 ನಲ್ಲಿ ದಕ್ಷ ಡೇಟಾ ವರ್ಗಾವಣೆಯ ಮೂಲಾಧಾರವಾಗಿದ್ದರೂ, ಗ್ರಾಫಿಕ್ಸ್ ಎಪಿಐಗಳ ಭೂದೃಶ್ಯವು ಯಾವಾಗಲೂ ವಿಕಸನಗೊಳ್ಳುತ್ತಿದೆ. WebGL ನ ಉತ್ತರಾಧಿಕಾರಿಯಾದ WebGPU ನಂತಹ ತಂತ್ರಜ್ಞಾನಗಳು, ಜಿಪಿಯು ಸಂಪನ್ಮೂಲಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ನಿರ್ವಹಿಸಲು ಇನ್ನಷ್ಟು ನೇರ ಮತ್ತು ಹೊಂದಿಕೊಳ್ಳುವ ಮಾರ್ಗಗಳನ್ನು ಪರಿಚಯಿಸುತ್ತವೆ. WebGPU ನ ಸ್ಪಷ್ಟ ಬೈಂಡಿಂಗ್ ಮಾದರಿ, ಕಂಪ್ಯೂಟ್ ಶೇಡರ್ಗಳು, ಮತ್ತು ಹೆಚ್ಚು ಆಧುನಿಕ ಬಫರ್ ನಿರ್ವಹಣೆ (ಉದಾ., ಸ್ಟೋರೇಜ್ ಬಫರ್ಗಳು, ಪ್ರತ್ಯೇಕ ಓದು/ಬರಹ ಪ್ರವೇಶ ಮಾದರಿಗಳು) ಇನ್ನಷ್ಟು ಸೂಕ್ಷ್ಮ-ಧಾನ್ಯದ ನಿಯಂತ್ರಣವನ್ನು ನೀಡುತ್ತವೆ ಮತ್ತು ಡ್ರೈವರ್ ಓವರ್ಹೆಡ್ ಅನ್ನು ಮತ್ತಷ್ಟು ಕಡಿಮೆ ಮಾಡುವ ಗುರಿಯನ್ನು ಹೊಂದಿವೆ, ಇದು ಹೆಚ್ಚಿನ ಕಾರ್ಯಕ್ಷಮತೆ ಮತ್ತು ಊಹಿಸುವಿಕೆಗೆ ಕಾರಣವಾಗುತ್ತದೆ, ವಿಶೇಷವಾಗಿ ಹೆಚ್ಚು ಸಮಾನಾಂತರ ಜಿಪಿಯು ಕೆಲಸದ ಹೊರೆಗಳಲ್ಲಿ.
ಆದಾಗ್ಯೂ, WebGL2 ಮತ್ತು UBOಗಳು ಮುಂದಿನ ಭವಿಷ್ಯಕ್ಕಾಗಿ ಹೆಚ್ಚು ಪ್ರಸ್ತುತವಾಗಿರುತ್ತವೆ, ವಿಶೇಷವಾಗಿ WebGL ನ ಪ್ರಪಂಚದಾದ್ಯಂತದ ಸಾಧನಗಳು ಮತ್ತು ಬ್ರೌಸರ್ಗಳಾದ್ಯಂತದ ವ್ಯಾಪಕ ಹೊಂದಾಣಿಕೆಯನ್ನು ಗಮನಿಸಿದರೆ. ಇಂದು UBOಗಳನ್ನು ಕರಗತ ಮಾಡಿಕೊಳ್ಳುವುದು ನಿಮಗೆ ಜಿಪಿಯು-ಬದಿಯ ಡೇಟಾ ನಿರ್ವಹಣೆ ಮತ್ತು ಮೆಮೊರಿ ಲೇಔಟ್ಗಳ ಮೂಲಭೂತ ಜ್ಞಾನವನ್ನು ನೀಡುತ್ತದೆ, ಅದು ಭವಿಷ್ಯದ ಗ್ರಾಫಿಕ್ಸ್ ಎಪಿಐಗಳಿಗೆ ಚೆನ್ನಾಗಿ ಅನುವಾದಿಸುತ್ತದೆ ಮತ್ತು WebGPU ಗೆ ಪರಿವರ್ತನೆಯನ್ನು ಹೆಚ್ಚು ಸುಗಮಗೊಳಿಸುತ್ತದೆ.
ತೀರ್ಮಾನ: ನಿಮ್ಮ WebGL ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಸಶಕ್ತಗೊಳಿಸುವುದು
ಯೂನಿಫಾರ್ಮ್ ಬಫರ್ ಆಬ್ಜೆಕ್ಟ್ಗಳು ಯಾವುದೇ ಗಂಭೀರ WebGL2 ಡೆವಲಪರ್ನ ಶಸ್ತ್ರಾಗಾರದಲ್ಲಿ ಅನಿವಾರ್ಯ ಸಾಧನವಾಗಿದೆ. UBOಗಳನ್ನು ಅರ್ಥಮಾಡಿಕೊಂಡು ಮತ್ತು ಸರಿಯಾಗಿ ಕಾರ್ಯಗತಗೊಳಿಸುವ ಮೂಲಕ, ನೀವು ಹೀಗೆ ಮಾಡಬಹುದು:
- ಸಿಪಿಯು-ಜಿಪಿಯು ಸಂವಹನ ಓವರ್ಹೆಡ್ ಅನ್ನು ಗಮನಾರ್ಹವಾಗಿ ಕಡಿಮೆ ಮಾಡಿ, ಹೆಚ್ಚಿನ ಫ್ರೇಮ್ ದರಗಳು ಮತ್ತು ಸುಗಮ ಸಂವಹನಗಳಿಗೆ ಕಾರಣವಾಗುತ್ತದೆ.
- ಸಂಕೀರ್ಣ ದೃಶ್ಯಗಳ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಸುಧಾರಿಸಿ, ವಿಶೇಷವಾಗಿ ಅನೇಕ ವಸ್ತುಗಳು, ಕ್ರಿಯಾತ್ಮಕ ಡೇಟಾ, ಅಥವಾ ಬಹು ರೆಂಡರಿಂಗ್ ಪಾಸ್ಗಳನ್ನು ಹೊಂದಿರುವವುಗಳು.
- ಶೇಡರ್ ಡೇಟಾ ನಿರ್ವಹಣೆಯನ್ನು ಸರಳೀಕರಿಸಿ, ನಿಮ್ಮ WebGL ಅಪ್ಲಿಕೇಶನ್ ಕೋಡ್ ಅನ್ನು ಸ್ವಚ್ಛ, ಹೆಚ್ಚು ಮಾಡ್ಯುಲರ್, ಮತ್ತು ನಿರ್ವಹಿಸಲು ಸುಲಭವಾಗಿಸುತ್ತದೆ.
- ದಕ್ಷ ಇನ್ಸ್ಟನ್ಸಿಂಗ್, ವಿಭಿನ್ನ ಶೇಡರ್ ಪ್ರೋಗ್ರಾಂಗಳಾದ್ಯಂತ ಹಂಚಿದ ಯೂನಿಫಾರ್ಮ್ ಸೆಟ್ಗಳು, ಮತ್ತು ಹೆಚ್ಚು ಅತ್ಯಾಧುನಿಕ ಲೈಟಿಂಗ್ ಅಥವಾ ವಸ್ತು ಮಾದರಿಗಳಂತಹ ಸುಧಾರಿತ ರೆಂಡರಿಂಗ್ ತಂತ್ರಗಳನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಿ.
ಆರಂಭಿಕ ಸೆಟಪ್ ಕಡಿದಾದ ಕಲಿಕೆಯ ರೇಖೆಯನ್ನು ಒಳಗೊಂಡಿದ್ದರೂ, ವಿಶೇಷವಾಗಿ ನಿಖರವಾದ `std140` ಲೇಔಟ್ ನಿಯಮಗಳ ಸುತ್ತ, ಕಾರ್ಯಕ್ಷಮತೆ, ಸ್ಕೇಲೆಬಿಲಿಟಿ, ಮತ್ತು ಕೋಡ್ ಸಂಘಟನೆಯ ವಿಷಯದಲ್ಲಿನ ಪ್ರಯೋಜನಗಳು ಹೂಡಿಕೆಗೆ ಯೋಗ್ಯವಾಗಿವೆ. ನೀವು ಜಾಗತಿಕ ಪ್ರೇಕ್ಷಕರಿಗಾಗಿ ಅತ್ಯಾಧುನಿಕ 3D ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ನಿರ್ಮಿಸುವುದನ್ನು ಮುಂದುವರಿಸಿದಂತೆ, ವೆಬ್-ಸಕ್ರಿಯಗೊಳಿಸಿದ ಸಾಧನಗಳ ವೈವಿಧ್ಯಮಯ ಪರಿಸರ ವ್ಯವಸ್ಥೆಯಾದ್ಯಂತ ಸುಗಮ, ಹೆಚ್ಚಿನ-ನಿಷ್ಠೆಯ ಅನುಭವಗಳನ್ನು ತಲುಪಿಸಲು UBOಗಳು ಪ್ರಮುಖ ಸಕ್ರಿಯಗೊಳಿಸುವಿಕೆಯಾಗಿರುತ್ತವೆ.
UBOಗಳನ್ನು ಅಳವಡಿಸಿಕೊಳ್ಳಿ, ಮತ್ತು ನಿಮ್ಮ WebGL ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಮುಂದಿನ ಹಂತಕ್ಕೆ ಕೊಂಡೊಯ್ಯಿರಿ!
ಹೆಚ್ಚಿನ ಓದು ಮತ್ತು ಸಂಪನ್ಮೂಲಗಳು
- MDN ವೆಬ್ ಡಾಕ್ಸ್: WebGL ಯೂನಿಫಾರ್ಮ್ ಗುಣಲಕ್ಷಣಗಳು - WebGL ಮೂಲಭೂತ ಅಂಶಗಳಿಗೆ ಉತ್ತಮ ಆರಂಭಿಕ ಬಿಂದು.
- OpenGL ವಿಕಿ: ಯೂನಿಫಾರ್ಮ್ ಬಫರ್ ಆಬ್ಜೆಕ್ಟ್ - OpenGL ನಲ್ಲಿ UBOಗಳಿಗಾಗಿ ವಿವರವಾದ ನಿರ್ದಿಷ್ಟತೆ.
- LearnOpenGL: ಸುಧಾರಿತ GLSL (ಯೂನಿಫಾರ್ಮ್ ಬಫರ್ ಆಬ್ಜೆಕ್ಟ್ಸ್ ವಿಭಾಗ) - GLSL ಮತ್ತು UBOಗಳನ್ನು ಅರ್ಥಮಾಡಿಕೊಳ್ಳಲು ಹೆಚ್ಚು ಶಿಫಾರಸು ಮಾಡಲಾದ ಸಂಪನ್ಮೂಲ.
- WebGL2 ಫಂಡಮೆಂಟಲ್ಸ್: ಯೂನಿಫಾರ್ಮ್ ಬಫರ್ಗಳು - ಪ್ರಾಯೋಗಿಕ WebGL2 ಉದಾಹರಣೆಗಳು ಮತ್ತು ವಿವರಣೆಗಳು.
- gl-matrix ಲೈಬ್ರರಿ ಜಾವಾಸ್ಕ್ರಿಪ್ಟ್ ವೆಕ್ಟರ್/ಮ್ಯಾಟ್ರಿಕ್ಸ್ ಗಣಿತಕ್ಕಾಗಿ - WebGL ನಲ್ಲಿ ಕಾರ್ಯಕ್ಷಮತೆಯ ಗಣಿತ ಕಾರ್ಯಾಚರಣೆಗಳಿಗೆ ಅವಶ್ಯಕ.
- Spector.js - ಒಂದು ಶಕ್ತಿಯುತ WebGL ಡೀಬಗ್ಗಿಂಗ್ ವಿಸ್ತರಣೆ.